@mock_only
Feature: TDD issue-capture tag validation
  As a developer writing TDD issue-capture tests
  I want the environment hooks to validate my tag combinations
  So that misconfigured TDD tests are caught before they run

  # Tests for the validate_tdd_tags() and should_invert_result() helper
  # functions defined in features/environment.py.
  # See CONTRIBUTING.md > TDD Issue Test Tags for the three-tag specification.

  # --- validate_tdd_tags: valid combinations ---

  Scenario: Valid TDD tags with all three tags present
    Given tdd tags a tag set with "tdd_issue, tdd_issue_123, tdd_expected_fail"
    When tdd tags I validate the tag set
    Then tdd tags validation should pass

  Scenario: Valid TDD tags with tdd_issue and tdd_issue_N only
    Given tdd tags a tag set with "tdd_issue, tdd_issue_456"
    When tdd tags I validate the tag set
    Then tdd tags validation should pass

  Scenario: Valid TDD tags with tdd_issue only
    Given tdd tags a tag set with "tdd_issue"
    When tdd tags I validate the tag set
    Then tdd tags validation should pass

  Scenario: Valid TDD tags with no TDD tags at all
    Given tdd tags a tag set with "wip, slow"
    When tdd tags I validate the tag set
    Then tdd tags validation should pass

  Scenario: Valid TDD tags with empty tag set
    Given tdd tags an empty tag set
    When tdd tags I validate the tag set
    Then tdd tags validation should pass

  # --- validate_tdd_tags: invalid combinations ---

  Scenario: Invalid TDD tags tdd_issue_N without tdd_issue raises error
    Given tdd tags a tag set with "tdd_issue_123"
    When tdd tags I validate the tag set
    Then tdd tags validation should fail with error containing "@tdd_issue"

  Scenario: Invalid TDD tags tdd_expected_fail without tdd_issue raises error
    Given tdd tags a tag set with "tdd_expected_fail, tdd_issue_123"
    When tdd tags I validate the tag set
    Then tdd tags validation should fail with error containing "@tdd_issue"

  Scenario: Invalid TDD tags tdd_expected_fail without tdd_issue_N raises error
    Given tdd tags a tag set with "tdd_expected_fail, tdd_issue"
    When tdd tags I validate the tag set
    Then tdd tags validation should fail with error containing "@tdd_issue_<N>"

  Scenario: Invalid TDD tags tdd_expected_fail alone raises error
    Given tdd tags a tag set with "tdd_expected_fail"
    When tdd tags I validate the tag set
    Then tdd tags validation should fail with error containing "@tdd_issue"

  Scenario: Invalid TDD tags multiple tdd_issue_N without tdd_issue raises error
    Given tdd tags a tag set with "tdd_issue_100, tdd_issue_200"
    When tdd tags I validate the tag set
    Then tdd tags validation should fail with error containing "@tdd_issue"

  # --- should_invert_result ---

  Scenario: should_invert_result returns True when tdd_expected_fail is present
    Given tdd tags a tag set with "tdd_issue, tdd_issue_42, tdd_expected_fail"
    Then tdd tags should_invert_result should return true

  Scenario: should_invert_result returns False when tdd_expected_fail is absent
    Given tdd tags a tag set with "tdd_issue, tdd_issue_42"
    Then tdd tags should_invert_result should return false

  Scenario: should_invert_result returns False for empty tag set
    Given tdd tags an empty tag set
    Then tdd tags should_invert_result should return false

  # --- apply_tdd_inversion: expected failure inverted to pass (happy path) ---

  Scenario: apply_tdd_inversion inverts expected AssertionError failure to pass
    Given tdd inversion a mock scenario that fails with AssertionError and tdd_expected_fail tags
    When tdd inversion apply_tdd_inversion is called with failed True
    Then tdd inversion the result should be False indicating expected failure was inverted
    And tdd inversion the scenario status should be passed
    And tdd inversion all failed and skipped steps should be reset to passed
    And tdd inversion all step error_messages should be cleared

  # --- apply_tdd_inversion: unexpected pass forces failure ---

  Scenario: apply_tdd_inversion forces failure when tdd_expected_fail scenario passes
    Given tdd inversion a mock scenario that passes with tdd_expected_fail tags
    When tdd inversion apply_tdd_inversion is called with failed False
    Then tdd inversion the result should be True indicating forced failure
    And tdd inversion the scenario status should be failed
    And tdd inversion the last step should have a synthetic error message
    And tdd inversion the last step should have a synthetic error_message text

  # --- apply_tdd_inversion: hook-error guard ---

  Scenario: apply_tdd_inversion does not invert when hook_failed is True
    Given tdd inversion a mock scenario with hook_failed and tdd_expected_fail tags
    When tdd inversion apply_tdd_inversion is called with failed True
    Then tdd inversion the result should be True indicating failure was not inverted

  # --- apply_tdd_inversion: dry-run guard ---

  Scenario: apply_tdd_inversion does not invert during dry-run mode
    Given tdd inversion a mock scenario in dry-run mode with tdd_expected_fail tags
    When tdd inversion apply_tdd_inversion is called with failed False
    Then tdd inversion the result should be False indicating no inversion occurred

  # --- apply_tdd_inversion: non-assertion exception guard ---

  Scenario: apply_tdd_inversion does not invert non-AssertionError exceptions
    Given tdd inversion a mock scenario with a RuntimeError and tdd_expected_fail tags
    When tdd inversion apply_tdd_inversion is called with failed True
    Then tdd inversion the result should be True indicating failure was not inverted

  # --- apply_tdd_inversion: empty steps edge case ---

  Scenario: apply_tdd_inversion handles unexpected pass with no steps
    Given tdd inversion a mock scenario with no steps and tdd_expected_fail tags
    When tdd inversion apply_tdd_inversion is called with failed False
    Then tdd inversion the result should be True indicating forced failure
    And tdd inversion the scenario status should be failed
