Feature: Robot TDD listener guard helper behaviour
  The pure Python guard helpers backing the Robot TDD listener should behave
  deterministically to avoid false positives or negatives. These scenarios
  exercise the infrastructure error detection, setup/teardown guard, and
  dry-run detection logic with representative inputs.

  Scenario Outline: Infrastructure error patterns are recognised
    When I evaluate the infrastructure guard for message "<message>"
    Then the infrastructure guard result is True

    Examples:
      | message |
      | No keyword with name Foo |
      | TypeError: bad call |
      | ImportError: missing module |
      | ModuleNotFoundError: mylib |
      | FileNotFoundError: config.json |
      | TimeoutError: network stalled |
      | PermissionError: denied |
      | OSError: device busy |
      | ConnectionError: dropped |
      | AttributeError: missing attr |
      | Connection refused by peer |
      | Connection reset by host |
      | Connection timed out after 5s |
      | No library with name FooLibrary |
      | Importing library FooLibrary failed |

  Scenario: Variable pattern matches Robot-style placeholders only
    When I evaluate the infrastructure guard for message "Variable '${FOO}' not found"
    Then the infrastructure guard result is True

  Scenario: Variable pattern ignores plain quoted values
    When I evaluate the infrastructure guard for message "Variable 'foo' not found"
    Then the infrastructure guard result is False

  Scenario: Normal assertion failure is not treated as infrastructure
    When I evaluate the infrastructure guard for message "AssertionError: expected 1 but got 2"
    Then the infrastructure guard result is False

  Scenario: Blank failure message is not treated as infrastructure
    When I evaluate the infrastructure guard for an empty message
    Then the infrastructure guard result is False

  Scenario: Setup failure flag triggers the setup/teardown guard
    Given a result with setup status "FAIL" and teardown status "PASS" and an empty message
    When I evaluate the setup teardown guard
    Then the setup teardown guard result is True

  Scenario: Teardown failure flag triggers the setup/teardown guard
    Given a result with setup status "PASS" and teardown status "FAIL" and an empty message
    When I evaluate the setup teardown guard
    Then the setup teardown guard result is True

  Scenario: Teardown failure message triggers the fallback detection
    Given a result with setup status "NONE" and teardown status "NONE" and message "Teardown failed: cleanup crashed"
    When I evaluate the setup teardown guard
    Then the setup teardown guard result is True

  Scenario: Setup failure message triggers the fallback detection
    Given a result with setup status "NONE" and teardown status "NONE" and message "Setup failed: database unavailable"
    When I evaluate the setup teardown guard
    Then the setup teardown guard result is True

  Scenario: Setup teardown guard ignores clean results
    Given a result with setup status "PASS" and teardown status "PASS" and message "All good"
    When I evaluate the setup teardown guard
    Then the setup teardown guard result is False

  Scenario: Dry-run guard leaves PASS results unchanged
    Given a tdd listener result with body keyword statuses
      | status   |
      | NOT RUN  |
      | NOT RUN  |
    And the result initial status is "PASS"
    When the listener processes the result with tags "tdd_issue tdd_issue_999 tdd_expected_fail"
    Then the processed result status is "PASS"

  Scenario: Dry-run guard allows inversion when keywords executed
    Given a tdd listener result with body keyword statuses
      | status |
      | PASS   |
    And the result initial status is "FAIL"
    When the listener processes the result with tags "tdd_issue tdd_issue_999 tdd_expected_fail"
    Then the processed result status is "PASS"
    And the processed result message contains "failed as expected"

  Scenario: Empty body does not trigger the dry-run guard
    Given a tdd listener result with body keyword statuses
      | status |
    And the result initial status is "FAIL"
    When the listener processes the result with tags "tdd_issue tdd_issue_999 tdd_expected_fail"
    Then the processed result status is "PASS"
