"""Step definitions for Action domain model tests.""" from typing import Any from behave import given, then, when from behave.runner import Context from pydantic import ValidationError from cleveragents.domain.models.core.action import ( Action, ActionArgument, ActionState, ArgumentRequirement, ArgumentType, ) from cleveragents.domain.models.core.plan import NamespacedName # --------------------------------------------------------------------------- # Helper # --------------------------------------------------------------------------- def _create_default_action( name: str = "local/test-action", definition_of_done: str = "Tests pass", **kwargs: Any, ) -> Action: """Helper to create an action with defaults.""" parsed_name = NamespacedName.parse(name) return Action( namespaced_name=parsed_name, description=kwargs.pop("description", "Default test action"), definition_of_done=definition_of_done, strategy_actor=kwargs.pop("strategy_actor", "openai/gpt-4"), execution_actor=kwargs.pop("execution_actor", "openai/gpt-4"), **kwargs, ) def _full_config(**overrides: Any) -> dict[str, Any]: """Return a minimal valid config dict for Action.from_config, with overrides.""" cfg: dict[str, Any] = { "name": "local/my-action", "description": "Run tests", "strategy_actor": "openai/gpt-4", "execution_actor": "openai/gpt-4", "definition_of_done": "All tests green", } cfg.update(overrides) return cfg # --------------------------------------------------------------------------- # ActionArgument Parsing Steps # --------------------------------------------------------------------------- @when('I parse the action argument "{arg_string}"') def step_parse_action_argument(context: Context, arg_string: str) -> None: """Parse an action argument string.""" context.argument = ActionArgument.parse(arg_string) context.parse_error = None @when('I try to parse the action argument "{arg_string}"') def step_try_parse_action_argument(context: Context, arg_string: str) -> None: """Attempt to parse an action argument string that might fail.""" context.parse_error = None try: context.argument = ActionArgument.parse(arg_string) except ValueError as e: context.parse_error = e @then('the argument name should be "{expected}"') def step_check_argument_name(context: Context, expected: str) -> None: """Check the argument name matches expected.""" assert context.argument.name == expected, ( f"Expected name '{expected}', got '{context.argument.name}'" ) @then('the argument type should be "{expected}"') def step_check_argument_type(context: Context, expected: str) -> None: """Check the argument type matches expected.""" actual = context.argument.arg_type.value assert actual == expected, f"Expected type '{expected}', got '{actual}'" @then("the argument should be required") def step_check_argument_required(context: Context) -> None: """Check the argument is required.""" assert context.argument.requirement == ArgumentRequirement.REQUIRED, ( f"Expected argument to be required, got {context.argument.requirement}" ) @then("the argument should be optional") def step_check_argument_optional(context: Context) -> None: """Check the argument is optional.""" assert context.argument.requirement == ArgumentRequirement.OPTIONAL, ( f"Expected argument to be optional, got {context.argument.requirement}" ) @then('the argument description should be "{expected}"') def step_check_argument_description(context: Context, expected: str) -> None: """Check the argument description matches expected.""" assert context.argument.description == expected, ( f"Expected description '{expected}', got '{context.argument.description}'" ) @then("the argument description should be empty") def step_check_argument_description_empty(context: Context) -> None: """Check the argument description is empty.""" assert context.argument.description == "", ( f"Expected empty description, got '{context.argument.description}'" ) @then("an argument parse error should be raised") def step_check_argument_parse_error(context: Context) -> None: """Verify that a parse error was raised.""" assert context.parse_error is not None, "Expected a parse error" @when('I try to create an action argument with invalid name "{name}"') def step_try_create_argument_with_invalid_name(context: Context, name: str) -> None: """Attempt to create an action argument with an invalid identifier name.""" context.error = None try: context.argument = ActionArgument( name=name, arg_type=ArgumentType.STRING, requirement=ArgumentRequirement.REQUIRED, description="Invalid name", ) except ValidationError as e: context.error = e @when("I stringify the action argument") def step_stringify_action_argument(context: Context) -> None: """Convert the action argument to its definition string.""" context.argument_string = str(context.argument) @then('the argument definition string should be "{expected}"') def step_check_argument_definition_string(context: Context, expected: str) -> None: """Verify the string representation of the action argument.""" assert context.argument_string == expected, ( f"Expected definition string '{expected}', got '{context.argument_string}'" ) # --------------------------------------------------------------------------- # Action Creation Steps # --------------------------------------------------------------------------- @when('I create an action with name "{name}" and definition of done "{dod}"') def step_create_action_with_name_dod(context: Context, name: str, dod: str) -> None: """Create an action with specified name and definition of done.""" context.action = _create_default_action(name=name, definition_of_done=dod) @when("I create a new action") def step_create_new_action(context: Context) -> None: """Create a new action with default values.""" context.action = _create_default_action() @given("I have action arguments") def step_have_action_arguments(context: Context) -> None: """Store action arguments from table.""" context.action_arguments = [] assert context.table is not None, "Expected table data for action arguments" for row in context.table: arg = ActionArgument( name=row["name"], arg_type=ArgumentType(row["type"]), requirement=ArgumentRequirement(row["requirement"]), description=row["description"], ) context.action_arguments.append(arg) @when("I create an action with these arguments") def step_create_action_with_arguments(context: Context) -> None: """Create an action with the stored arguments.""" context.action = _create_default_action(arguments=context.action_arguments) @then("the action should be created") def step_check_action_created(context: Context) -> None: """Verify the action was created.""" assert context.action is not None, "Action should be created" @then('the action namespace should be "{expected}"') def step_check_action_namespace(context: Context, expected: str) -> None: """Check the action namespace matches expected.""" actual = context.action.namespaced_name.namespace assert actual == expected, f"Expected namespace '{expected}', got '{actual}'" @then('the action name should be "{expected}"') def step_check_action_name(context: Context, expected: str) -> None: """Check the action name matches expected.""" actual = context.action.namespaced_name.name assert actual == expected, f"Expected name '{expected}', got '{actual}'" @then('the action state should be "{expected}"') def step_check_action_state(context: Context, expected: str) -> None: """Check the action state matches expected.""" actual = context.action.state.value assert actual == expected, f"Expected state '{expected}', got '{actual}'" @then("the action should have {count:d} arguments") def step_check_argument_count(context: Context, count: int) -> None: """Check the number of arguments.""" actual = len(context.action.arguments) assert actual == count, f"Expected {count} arguments, got {actual}" @then("the action should have {count:d} required argument") def step_check_required_argument_count(context: Context, count: int) -> None: """Check the number of required arguments.""" actual = len(context.action.required_arguments) assert actual == count, f"Expected {count} required arguments, got {actual}" @then("the action should have {count:d} optional argument") def step_check_optional_argument_count(context: Context, count: int) -> None: """Check the number of optional arguments.""" actual = len(context.action.optional_arguments) assert actual == count, f"Expected {count} optional arguments, got {actual}" # --------------------------------------------------------------------------- # Argument Validation Steps # --------------------------------------------------------------------------- @given('I have an action with required argument "{arg_string}"') def step_have_action_with_required_arg(context: Context, arg_string: str) -> None: """Create an action with a required argument.""" arg = ActionArgument.parse(arg_string) context.action = _create_default_action(arguments=[arg]) @when("I validate arguments with target {value:d}") def step_validate_arguments_with_target(context: Context, value: int) -> None: """Validate arguments with target value.""" context.errors = context.action.validate_arguments({"target": value}) @when("I validate arguments without target") def step_validate_arguments_without_target(context: Context) -> None: """Validate arguments without providing target.""" context.errors = context.action.validate_arguments({}) @when('I validate arguments with target {value:d} and extra "{extra}"') def step_validate_arguments_with_extra( context: Context, value: int, extra: str ) -> None: """Validate arguments with an extra unknown argument.""" context.errors = context.action.validate_arguments( { "target": value, "extra": extra, } ) @when('I validate arguments with target as string "{value}"') def step_validate_arguments_with_string_target(context: Context, value: str) -> None: """Validate arguments with target as wrong type.""" context.errors = context.action.validate_arguments({"target": value}) @given( 'I have an action with bounded integer argument "{name}" min {min_value:d} max {max_value:d}' ) def step_have_action_with_bounded_integer( context: Context, name: str, min_value: int, max_value: int ) -> None: """Create an action with a bounded integer argument.""" arg = ActionArgument( name=name, arg_type=ArgumentType.INTEGER, requirement=ArgumentRequirement.REQUIRED, description="Bounded integer argument", min_value=min_value, max_value=max_value, ) context.action = _create_default_action(arguments=[arg]) @given('I have an action with argument "{name}" of type "{arg_type}"') def step_have_action_with_argument_type( context: Context, name: str, arg_type: str ) -> None: """Create an action with an argument of a specific type.""" arg = ActionArgument( name=name, arg_type=ArgumentType(arg_type), requirement=ArgumentRequirement.REQUIRED, description=f"{arg_type} argument", ) context.action = _create_default_action(arguments=[arg]) @when('I validate arguments with "{name}" set to {value:d}') def step_validate_arguments_with_named_int( context: Context, name: str, value: int ) -> None: """Validate arguments with a named integer value.""" context.errors = context.action.validate_arguments({name: value}) @when('I validate arguments with "{name}" set to "{value}"') def step_validate_arguments_with_named_string( context: Context, name: str, value: str ) -> None: """Validate arguments with a named string value.""" context.errors = context.action.validate_arguments({name: value}) @then("the validation should pass") def step_check_validation_pass(context: Context) -> None: """Check that validation passed.""" assert len(context.errors) == 0, ( f"Expected validation to pass, got errors: {context.errors}" ) @then('the validation should fail with "{expected_msg}"') def step_check_validation_fail(context: Context, expected_msg: str) -> None: """Check that validation failed with expected message.""" assert len(context.errors) > 0, "Expected validation errors" error_text = " ".join(context.errors) assert expected_msg in error_text, ( f"Expected error containing '{expected_msg}', got: {context.errors}" ) # --------------------------------------------------------------------------- # Action State Steps # --------------------------------------------------------------------------- @given("I have an available action") def step_have_available_action(context: Context) -> None: """Create an action in available state.""" context.action = _create_default_action() context.action.state = ActionState.AVAILABLE @when("I set the action state to archived") def step_set_action_archived(context: Context) -> None: """Set action state to archived.""" context.action.state = ActionState.ARCHIVED # --------------------------------------------------------------------------- # Actor Configuration Steps # --------------------------------------------------------------------------- @when("I try to create an action without strategy actor") def step_try_create_action_without_strategy_actor(context: Context) -> None: """Attempt to create an action without strategy actor.""" context.error = None try: data = { "namespaced_name": NamespacedName.parse("local/test"), "description": "Test action", "definition_of_done": "Test", # Missing strategy_actor "execution_actor": "openai/gpt-4", } context.action = Action.model_validate(data) except ValidationError as e: context.error = e context.action = None # Note: "a validation error should be raised" step is defined in domain_models_steps.py @when('I create an action with review actor "{actor}"') def step_create_action_with_review_actor(context: Context, actor: str) -> None: """Create an action with a review actor.""" context.action = _create_default_action(review_actor=actor) @when('I create an action with estimation actor "{actor}"') def step_create_action_with_estimation_actor(context: Context, actor: str) -> None: """Create an action with an estimation actor.""" context.action = _create_default_action(estimation_actor=actor) @then("the action should have a review actor") def step_check_has_review_actor(context: Context) -> None: """Check the action has a review actor.""" assert context.action.review_actor is not None, "Expected review actor" @then("the action should have an estimation actor") def step_check_has_estimation_actor(context: Context) -> None: """Check the action has an estimation actor.""" assert context.action.estimation_actor is not None, "Expected estimation actor" # --------------------------------------------------------------------------- # Reusability Steps # --------------------------------------------------------------------------- @when("I create a non-reusable action") def step_create_non_reusable_action(context: Context) -> None: """Create a non-reusable action.""" context.action = _create_default_action(reusable=False) @then("the action should be reusable") def step_check_action_reusable(context: Context) -> None: """Check the action is reusable.""" assert context.action.reusable is True, "Expected action to be reusable" @then("the action should not be reusable") def step_check_action_not_reusable(context: Context) -> None: """Check the action is not reusable.""" assert context.action.reusable is False, "Expected action to not be reusable" # --------------------------------------------------------------------------- # Read-only Steps # --------------------------------------------------------------------------- @when("I create a read-only action") def step_create_read_only_action(context: Context) -> None: """Create a read-only action.""" context.action = _create_default_action(read_only=True) @then("the action should be read-only") def step_check_action_read_only(context: Context) -> None: """Check the action is read-only.""" assert context.action.read_only is True, "Expected action to be read-only" @then("the action should not be read-only") def step_check_action_not_read_only(context: Context) -> None: """Check the action is not read-only.""" assert context.action.read_only is False, "Expected action to not be read-only" # --------------------------------------------------------------------------- # Invariants Sanitization Steps # --------------------------------------------------------------------------- @when( "I create an action model with invariants " '" no secrets " and "" and " no secrets" and "keep data safe"' ) def step_create_action_model_with_invariants(context: Context) -> None: """Create an action with invariants that need sanitization.""" context.action = _create_default_action( invariants=[" no secrets ", "", " no secrets", "keep data safe"], ) @then('the action model invariants should be "{first}" and "{second}"') def step_check_action_model_invariants( context: Context, first: str, second: str ) -> None: """Check the sanitized invariants list.""" assert context.action.invariants == [first, second], ( f"Expected [{first}, {second}], got {context.action.invariants}" ) @when("I create an action model with null invariants") def step_create_action_model_with_null_invariants(context: Context) -> None: """Create an action with None invariants (should default to []).""" context.action = _create_default_action(invariants=None) @then("the action model invariants count should be {count:d}") def step_check_action_model_invariants_count(context: Context, count: int) -> None: """Check the invariants list length.""" actual = len(context.action.invariants) assert actual == count, f"Expected {count} invariants, got {actual}" # --------------------------------------------------------------------------- # from_config Factory Steps # --------------------------------------------------------------------------- @when( 'I create an action model from config with name "{name}" ' 'and description "{desc}" and dod "{dod}"' ) def step_create_action_model_from_config( context: Context, name: str, desc: str, dod: str ) -> None: """Create an action via from_config.""" config = _full_config(name=name, description=desc, definition_of_done=dod) context.action = Action.from_config(config) @then('the action model description should be "{expected}"') def step_check_action_model_description(context: Context, expected: str) -> None: """Check the action description.""" assert context.action.description == expected, ( f"Expected description '{expected}', got '{context.action.description}'" ) @when("I create an action model from config with arguments") def step_create_action_model_from_config_with_args(context: Context) -> None: """Create an action via from_config with argument mappings.""" config = _full_config( arguments=[ { "name": "target", "type": "integer", "required": True, "description": "Target value", }, { "name": "mode", "type": "string", "required": False, "description": "Mode", "default": "fast", }, ], ) context.action = Action.from_config(config) @when('I try to create an action model from config missing "{field}"') def step_try_create_action_model_from_config_missing( context: Context, field: str ) -> None: """Try from_config with a missing required field.""" config = _full_config() del config[field] context.action_model_config_error = None try: context.action = Action.from_config(config) except ValueError as e: context.action_model_config_error = e @then('an action model config error should be raised with "{field}"') def step_check_action_model_config_error(context: Context, field: str) -> None: """Check that a config error mentioning the field was raised.""" assert context.action_model_config_error is not None, ( f"Expected ValueError for missing '{field}'" ) assert field in str(context.action_model_config_error), ( f"Expected error to mention '{field}', got: {context.action_model_config_error}" ) # --------------------------------------------------------------------------- # as_cli_dict Steps # --------------------------------------------------------------------------- @when("I create an action model and call as_cli_dict") def step_create_action_model_and_cli_dict(context: Context) -> None: """Create an action and get its CLI dict.""" context.action = _create_default_action() context.action_model_cli_dict = context.action.as_cli_dict() @then('the action model cli dict should have key "{key}"') def step_check_action_model_cli_dict_key(context: Context, key: str) -> None: """Check the CLI dict contains a key.""" assert key in context.action_model_cli_dict, ( f"Expected key '{key}' in cli dict, keys: {list(context.action_model_cli_dict)}" ) @when("I create an action model with review actor and call as_cli_dict") def step_create_action_model_with_review_and_cli_dict(context: Context) -> None: """Create an action with review actor and get CLI dict.""" context.action = _create_default_action(review_actor="local/reviewer") context.action_model_cli_dict = context.action.as_cli_dict() @when("I create an action model with arguments and call as_cli_dict") def step_create_action_model_with_args_and_cli_dict(context: Context) -> None: """Create an action with arguments and get CLI dict.""" arg = ActionArgument( name="target", arg_type=ArgumentType.INTEGER, requirement=ArgumentRequirement.REQUIRED, description="Target value", ) context.action = _create_default_action(arguments=[arg]) context.action_model_cli_dict = context.action.as_cli_dict() @then("the action model cli dict arguments count should be {count:d}") def step_check_action_model_cli_dict_args_count(context: Context, count: int) -> None: """Check the number of arguments in the CLI dict.""" actual = len(context.action_model_cli_dict["arguments"]) assert actual == count, f"Expected {count} arguments in cli dict, got {actual}" # --------------------------------------------------------------------------- # from_mapping Steps (ActionArgument) # --------------------------------------------------------------------------- @when( 'I create an action argument from basic mapping "{name}" ' 'type "{arg_type}" required {req}' ) def step_create_action_argument_from_mapping( context: Context, name: str, arg_type: str, req: str ) -> None: """Create an ActionArgument via from_mapping.""" required = req.lower() == "true" context.argument = ActionArgument.from_mapping( {"name": name, "type": arg_type, "required": required} ) @when( 'I create an action argument from mapping with default "{name}" ' 'type "{arg_type}" required {req} default "{default}"' ) def step_create_action_argument_from_mapping_with_default( context: Context, name: str, arg_type: str, req: str, default: str ) -> None: """Create an ActionArgument via from_mapping with a default value.""" required = req.lower() == "true" context.argument = ActionArgument.from_mapping( {"name": name, "type": arg_type, "required": required, "default": default} ) @then('the action model argument default value should be "{expected}"') def step_check_action_model_argument_default(context: Context, expected: str) -> None: """Check the argument default value.""" assert context.argument.default_value == expected, ( f"Expected default '{expected}', got '{context.argument.default_value}'" ) @when("I try to create an action argument from mapping missing name") def step_try_create_argument_from_mapping_missing_name(context: Context) -> None: """Try from_mapping without 'name'.""" context.action_model_arg_mapping_error = None try: ActionArgument.from_mapping({"type": "string"}) except ValueError as e: context.action_model_arg_mapping_error = e @when("I try to create an action argument from mapping missing type") def step_try_create_argument_from_mapping_missing_type(context: Context) -> None: """Try from_mapping without 'type'.""" context.action_model_arg_mapping_error = None try: ActionArgument.from_mapping({"name": "foo"}) except ValueError as e: context.action_model_arg_mapping_error = e @then('an action model argument mapping error should be raised with "{field}"') def step_check_action_model_arg_mapping_error(context: Context, field: str) -> None: """Check that a mapping error mentioning the field was raised.""" assert context.action_model_arg_mapping_error is not None, ( f"Expected ValueError for missing '{field}'" ) assert field in str(context.action_model_arg_mapping_error), ( f"Expected error to mention '{field}', " f"got: {context.action_model_arg_mapping_error}" ) # --------------------------------------------------------------------------- # coerce_value Steps # --------------------------------------------------------------------------- @given('I have an action model string argument named "{name}"') def step_have_action_model_string_argument(context: Context, name: str) -> None: """Create a string ActionArgument.""" context.action_model_arg = ActionArgument( name=name, arg_type=ArgumentType.STRING, requirement=ArgumentRequirement.REQUIRED, ) @given('I have an action model integer argument named "{name}"') def step_have_action_model_integer_argument(context: Context, name: str) -> None: """Create an integer ActionArgument.""" context.action_model_arg = ActionArgument( name=name, arg_type=ArgumentType.INTEGER, requirement=ArgumentRequirement.REQUIRED, ) @given('I have an action model float argument named "{name}"') def step_have_action_model_float_argument(context: Context, name: str) -> None: """Create a float ActionArgument.""" context.action_model_arg = ActionArgument( name=name, arg_type=ArgumentType.FLOAT, requirement=ArgumentRequirement.REQUIRED, ) @given('I have an action model boolean argument named "{name}"') def step_have_action_model_boolean_argument(context: Context, name: str) -> None: """Create a boolean ActionArgument.""" context.action_model_arg = ActionArgument( name=name, arg_type=ArgumentType.BOOLEAN, requirement=ArgumentRequirement.REQUIRED, ) @given('I have an action model list argument named "{name}"') def step_have_action_model_list_argument(context: Context, name: str) -> None: """Create a list ActionArgument.""" context.action_model_arg = ActionArgument( name=name, arg_type=ArgumentType.LIST, requirement=ArgumentRequirement.REQUIRED, ) @when('I coerce action model value "{raw}" for the argument') def step_coerce_action_model_value(context: Context, raw: str) -> None: """Coerce a raw string value using the stored argument.""" context.coerced_action_model_value = context.action_model_arg.coerce_value(raw) @when('I try to coerce action model value "{raw}" for the argument') def step_try_coerce_action_model_value(context: Context, raw: str) -> None: """Try to coerce a value that may fail.""" context.action_model_coerce_error = None try: context.coerced_action_model_value = context.action_model_arg.coerce_value(raw) except ValueError as e: context.action_model_coerce_error = e @then('the coerced action model value should be string "{expected}"') def step_check_coerced_action_model_string(context: Context, expected: str) -> None: """Check the coerced value is the expected string.""" assert context.coerced_action_model_value == expected, ( f"Expected '{expected}', got '{context.coerced_action_model_value}'" ) @then("the coerced action model value should be integer {expected:d}") def step_check_coerced_action_model_integer(context: Context, expected: int) -> None: """Check the coerced value is the expected integer.""" assert context.coerced_action_model_value == expected, ( f"Expected {expected}, got {context.coerced_action_model_value}" ) assert isinstance(context.coerced_action_model_value, int) @then("the coerced action model value should be float {expected:g}") def step_check_coerced_action_model_float(context: Context, expected: float) -> None: """Check the coerced value is the expected float.""" assert abs(context.coerced_action_model_value - expected) < 1e-9, ( f"Expected {expected}, got {context.coerced_action_model_value}" ) @then("the coerced action model value should be boolean true") def step_check_coerced_action_model_bool_true(context: Context) -> None: """Check the coerced value is True.""" assert context.coerced_action_model_value is True, ( f"Expected True, got {context.coerced_action_model_value}" ) @then("the coerced action model value should be boolean false") def step_check_coerced_action_model_bool_false(context: Context) -> None: """Check the coerced value is False.""" assert context.coerced_action_model_value is False, ( f"Expected False, got {context.coerced_action_model_value}" ) @then("an action model coerce error should be raised") def step_check_action_model_coerce_error(context: Context) -> None: """Check that a coerce error was raised.""" assert context.action_model_coerce_error is not None, ( "Expected ValueError from coerce_value" ) @then("the coerced action model value should be list with {count:d} items") def step_check_coerced_action_model_list(context: Context, count: int) -> None: """Check the coerced value is a list of the expected length.""" assert isinstance(context.coerced_action_model_value, list), ( f"Expected list, got {type(context.coerced_action_model_value)}" ) actual = len(context.coerced_action_model_value) assert actual == count, f"Expected {count} items, got {actual}" # --------------------------------------------------------------------------- # render_template Steps # --------------------------------------------------------------------------- @when('I create an action model with description "{desc}"') def step_create_action_model_with_description(context: Context, desc: str) -> None: """Create an action with a template description.""" context.action = _create_default_action(description=desc) @when('I render action model description with target "{target}" and module "{module}"') def step_render_action_model_description( context: Context, target: str, module: str ) -> None: """Render the description template.""" context.rendered_action_model_desc = context.action.render_description( {"target": target, "module": module} ) @then('the rendered action model description should be "{expected}"') def step_check_rendered_action_model_description( context: Context, expected: str ) -> None: """Check the rendered description.""" assert context.rendered_action_model_desc == expected, ( f"Expected '{expected}', got '{context.rendered_action_model_desc}'" ) @when('I try to render action model description with only target "{target}"') def step_try_render_action_model_desc_incomplete(context: Context, target: str) -> None: """Try to render the description with missing placeholders.""" context.action_model_template_error = None try: context.action.render_description({"target": target}) except ValueError as e: context.action_model_template_error = e @then("an action model template error should be raised") def step_check_action_model_template_error(context: Context) -> None: """Check that a template rendering error was raised.""" assert context.action_model_template_error is not None, ( "Expected ValueError from render_template" ) @when("I create an action model with dod template for module and target") def step_create_action_model_with_dod_template(context: Context) -> None: """Create an action with a template definition of done.""" context.action = _create_default_action( definition_of_done="All tests in ${module} pass with ${target}% coverage", ) @when('I render action model dod with target "{target}" and module "{module}"') def step_render_action_model_dod(context: Context, target: str, module: str) -> None: """Render the definition of done template.""" context.rendered_action_model_dod = context.action.render_definition_of_done( {"target": target, "module": module} ) @then('the rendered action model dod should be "{expected}"') def step_check_rendered_action_model_dod(context: Context, expected: str) -> None: """Check the rendered definition of done.""" assert context.rendered_action_model_dod == expected, ( f"Expected '{expected}', got '{context.rendered_action_model_dod}'" ) # --------------------------------------------------------------------------- # inputs_schema Validation Steps # --------------------------------------------------------------------------- @when( 'I create an action model with inputs schema type "{schema_type}" ' 'and required "{req_field}"' ) def step_create_action_model_with_inputs_schema( context: Context, schema_type: str, req_field: str ) -> None: """Create an action with a valid inputs_schema dict.""" context.action = _create_default_action( inputs_schema={"type": schema_type, "required": [req_field]}, ) @when("I create an action model with null inputs schema") def step_create_action_model_with_null_inputs_schema(context: Context) -> None: """Create an action with inputs_schema=None.""" context.action = _create_default_action(inputs_schema=None) @then("the action model inputs schema should not be none") def step_check_action_model_inputs_schema_not_none(context: Context) -> None: """Check inputs_schema is set.""" assert context.action.inputs_schema is not None, "Expected inputs_schema to be set" @then("the action model inputs schema should be none") def step_check_action_model_inputs_schema_none(context: Context) -> None: """Check inputs_schema is None.""" assert context.action.inputs_schema is None, ( f"Expected inputs_schema to be None, got {context.action.inputs_schema}" ) @when("I try to create an action model with inputs schema as string") def step_try_create_action_model_with_bad_inputs_schema(context: Context) -> None: """Try to create an action with inputs_schema as a non-dict.""" context.error = None try: context.action = _create_default_action(inputs_schema="not a dict") except ValidationError as e: context.error = e # --------------------------------------------------------------------------- # automation_profile Validation Steps # --------------------------------------------------------------------------- @when('I create an action model with automation profile "{profile}"') def step_create_action_model_with_automation_profile( context: Context, profile: str ) -> None: """Create an action with an automation_profile.""" context.action = _create_default_action(automation_profile=profile) @then('the action model automation profile should be "{expected}"') def step_check_action_model_automation_profile(context: Context, expected: str) -> None: """Check the automation_profile value.""" assert context.action.automation_profile == expected, ( f"Expected '{expected}', got '{context.action.automation_profile}'" ) @then("the action model automation profile should be none") def step_check_action_model_automation_profile_none(context: Context) -> None: """Check that automation_profile is None.""" assert context.action.automation_profile is None, ( f"Expected None, got '{context.action.automation_profile}'" ) @when("I create an action model with null automation profile") def step_create_action_model_with_null_automation_profile(context: Context) -> None: """Create an action with automation_profile=None.""" context.action = _create_default_action(automation_profile=None)