"""Step definitions for Settings spec-required env var fields (issue #2866).""" from __future__ import annotations import os from behave import given, then, when from cleveragents.config.settings import Settings _SPEC_FIELD_ENV_VARS = [ "CLEVERAGENTS_SERVER_URL", "CLEVERAGENTS_SERVER_TOKEN", "CLEVERAGENTS_FORMAT", "CLEVERAGENTS_DEFAULT_ESTIMATION_ACTOR", ] @given("no CleverAgents spec-field env vars are set") def step_clear_spec_field_env_vars(context): """Remove all spec-field env vars so Settings starts from a clean slate.""" for key in _SPEC_FIELD_ENV_VARS: os.environ.pop(key, None) if not hasattr(context, "env_vars_to_clean"): context.env_vars_to_clean = [] context.env_vars_to_clean.extend(_SPEC_FIELD_ENV_VARS) @when("I instantiate Settings for spec fields") def step_instantiate_settings_for_spec_fields(context): """Create a fresh Settings instance (bypassing the singleton).""" Settings._instance = None context.settings = Settings() @when("I inspect Settings.model_fields") def step_inspect_model_fields(context): """Capture the model_fields mapping for assertion.""" context.model_fields = Settings.model_fields # ── server_url assertions ──────────────────────────────────────────────────── @then("settings.server_url should be None") def step_server_url_is_none(context): assert context.settings.server_url is None, ( f"Expected server_url to be None, got {context.settings.server_url!r}" ) @then('settings.server_url should be "{expected}"') def step_server_url_equals(context, expected): assert context.settings.server_url == expected, ( f"Expected server_url={expected!r}, got {context.settings.server_url!r}" ) # ── server_token assertions ────────────────────────────────────────────────── @then("settings.server_token should be None") def step_server_token_is_none(context): assert context.settings.server_token is None, ( f"Expected server_token to be None, got {context.settings.server_token!r}" ) @then('settings.server_token should be "{expected}"') def step_server_token_equals(context, expected): assert context.settings.server_token == expected, ( f"Expected server_token={expected!r}, got {context.settings.server_token!r}" ) # ── format assertions ──────────────────────────────────────────────────────── @then("settings.format should be None") def step_format_is_none(context): assert context.settings.format is None, ( f"Expected format to be None, got {context.settings.format!r}" ) @then('settings.format should be "{expected}"') def step_format_equals(context, expected): assert context.settings.format == expected, ( f"Expected format={expected!r}, got {context.settings.format!r}" ) # ── default_estimation_actor assertions ────────────────────────────────────── @then("settings.default_estimation_actor should be None") def step_default_estimation_actor_is_none(context): assert context.settings.default_estimation_actor is None, ( "Expected default_estimation_actor to be None, " f"got {context.settings.default_estimation_actor!r}" ) @then('settings.default_estimation_actor should be "{expected}"') def step_default_estimation_actor_equals(context, expected): assert context.settings.default_estimation_actor == expected, ( f"Expected default_estimation_actor={expected!r}, " f"got {context.settings.default_estimation_actor!r}" ) # ── model_fields presence assertions ───────────────────────────────────────── @then('"{field_name}" should be present in model_fields') def step_field_in_model_fields(context, field_name): assert field_name in context.model_fields, ( f"Expected '{field_name}' to be in Settings.model_fields, " f"but only found: {sorted(context.model_fields.keys())}" ) # ── type annotation assertions ─────────────────────────────────────────────── @then("settings.server_url should be of type str or None") def step_server_url_type(context): value = context.settings.server_url assert value is None or isinstance(value, str), ( f"Expected server_url to be str | None, got {type(value)}" ) @then("settings.server_token should be of type str or None") def step_server_token_type(context): value = context.settings.server_token assert value is None or isinstance(value, str), ( f"Expected server_token to be str | None, got {type(value)}" ) @then("settings.format should be of type str or None") def step_format_type(context): value = context.settings.format assert value is None or isinstance(value, str), ( f"Expected format to be str | None, got {type(value)}" ) @then("settings.default_estimation_actor should be of type str or None") def step_default_estimation_actor_type(context): value = context.settings.default_estimation_actor assert value is None or isinstance(value, str), ( f"Expected default_estimation_actor to be str | None, got {type(value)}" )