*** Settings ***
Documentation    Integration tests for TDD issue-capture tag validation and
...              result-inversion logic.  Covers both the Behave implementation
...              (``features/environment.py``: ``validate_tdd_tags()``,
...              ``should_invert_result()``, ``apply_tdd_inversion()``) and the
...              Robot Framework listener (``tdd_expected_fail_listener.py``).
...
...              Robot-side tests run fixture ``.robot`` files via a helper
...              script that launches Robot with the listener active, then
...              checks the final test status in the output XML.
...
...              See CONTRIBUTING.md > TDD Issue Test Tags for the full
...              specification.
Resource         ${CURDIR}/common.resource
Suite Setup      Setup Test Environment
Suite Teardown   Cleanup Test Environment

*** Variables ***
${HELPER}    ${CURDIR}/helper_tdd_tag_validation.py

*** Test Cases ***
# ===========================================================================
# Behave-side tests (features/environment.py)
# ===========================================================================

Valid Tag Combinations Are Accepted
    [Documentation]    Verify valid TDD tag sets raise no errors
    [Tags]    testing    tdd    validation
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    validate_tags_valid_combos
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    validate-tags-valid-combos-ok

Issue N Without Issue Tag Raises Error
    [Documentation]    Verify tdd_issue_<N> without tdd_issue raises ValueError
    [Tags]    testing    tdd    validation
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    validate_tags_issue_n_without_issue
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    validate-tags-issue-n-without-issue-ok

Expected Fail Without Issue Tag Raises Error
    [Documentation]    Verify tdd_expected_fail without tdd_issue raises ValueError
    [Tags]    testing    tdd    validation
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    validate_tags_expected_fail_missing_issue
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    validate-tags-expected-fail-missing-issue-ok

Expected Fail Without Issue N Tag Raises Error
    [Documentation]    Verify tdd_expected_fail without tdd_issue_<N> raises ValueError
    [Tags]    testing    tdd    validation
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    validate_tags_expected_fail_missing_issue_n
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    validate-tags-expected-fail-missing-issue-n-ok

Should Invert With Expected Fail Tag
    [Documentation]    Verify should_invert_result returns True with tdd_expected_fail
    [Tags]    testing    tdd    inversion
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    should_invert_with_expected_fail
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    should-invert-with-expected-fail-ok

Should Not Invert Without Expected Fail Tag
    [Documentation]    Verify should_invert_result returns False without tdd_expected_fail
    [Tags]    testing    tdd    inversion
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    should_not_invert_without_expected_fail
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    should-not-invert-without-expected-fail-ok

Inversion Expected Fail Is Inverted To Pass
    [Documentation]    Verify a failed tdd_expected_fail scenario is inverted to passed
    [Tags]    testing    tdd    inversion
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    inversion_expected_fail
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    inversion-expected-fail-ok

Inversion Unexpected Pass Forces Failure
    [Documentation]    Verify a passing tdd_expected_fail scenario is forced to fail
    ...               with a synthetic error attached to the last step
    [Tags]    testing    tdd    inversion
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    inversion_unexpected_pass
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    inversion-unexpected-pass-ok

Inversion Hook Error Guard Prevents Inversion
    [Documentation]    Verify hook_failed=True prevents result inversion
    [Tags]    testing    tdd    inversion    guard
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    inversion_hook_error_guard
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    inversion-hook-error-guard-ok

Inversion Dry Run Guard Prevents Inversion
    [Documentation]    Verify dry-run mode prevents result inversion
    [Tags]    testing    tdd    inversion    guard
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    inversion_dry_run_guard
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    inversion-dry-run-guard-ok

Inversion Non Assertion Guard Prevents Inversion
    [Documentation]    Verify non-AssertionError exceptions prevent result inversion
    [Tags]    testing    tdd    inversion    guard
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    inversion_non_assertion_guard
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    inversion-non-assertion-guard-ok

Inversion No Tag Passthrough
    [Documentation]    Verify scenarios without tdd_expected_fail are not modified
    [Tags]    testing    tdd    inversion
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    inversion_no_tag_passthrough
    ...    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    inversion-no-tag-passthrough-ok

# ===========================================================================
# Robot-side tests (tdd_expected_fail_listener.py)
# ===========================================================================

TDD Expected Fail Test That Fails Is Inverted To Pass
    [Documentation]    A test tagged ``tdd_expected_fail`` that deliberately fails
    ...    should have its result inverted to PASS by the listener (bug still exists).
    [Tags]    tdd_infrastructure
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    expected-fail-inverted    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-expected-fail-inverted-ok

TDD Expected Fail Test That Passes Is Inverted To Fail
    [Documentation]    A test tagged ``tdd_expected_fail`` that unexpectedly passes
    ...    should have its result inverted to FAIL with a guidance message telling the
    ...    developer to remove the tag.
    [Tags]    tdd_infrastructure
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    unexpected-pass-inverted    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-unexpected-pass-inverted-ok

TDD Tag Validation Catches Missing tdd_issue
    [Documentation]    A test with ``tdd_issue_<N>`` but missing ``tdd_issue`` should
    ...    fail with a clear validation error message.
    [Tags]    tdd_infrastructure
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    missing-tdd-issue-validation    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-missing-tdd-issue-validation-ok

TDD Tag Validation Catches Missing tdd_issue_N
    [Documentation]    A test with ``tdd_expected_fail`` and ``tdd_issue`` but missing
    ...    ``tdd_issue_<N>`` should fail with a clear validation error message.
    [Tags]    tdd_infrastructure
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    missing-issue-n-validation    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-missing-issue-n-validation-ok

Normal Test Unaffected By TDD Listener
    [Documentation]    A test with no TDD tags run alongside a tdd_expected_fail test
    ...    should be completely unaffected by the listener. Proves the listener is
    ...    loaded (the companion fixture is inverted) but does not modify normal tests.
    [Tags]    tdd_infrastructure
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    normal-test-unaffected    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-normal-test-unaffected-ok

TDD Expected Fail Skip Status Is Unchanged
    [Documentation]    A ``tdd_expected_fail`` test that is skipped should stay SKIP.
    ...    The listener should not treat a skipped test as evidence of a fix.
    [Tags]    tdd_infrastructure
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    skip-status-unchanged    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-skip-status-unchanged-ok

TDD Tag Validation Catches Expected Fail Alone
    [Documentation]    A test with only ``tdd_expected_fail`` (both ``tdd_issue`` and
    ...    ``tdd_issue_<N>`` missing) should fail with validation error mentioning both.
    [Tags]    tdd_infrastructure
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    expected-fail-alone-validation    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-expected-fail-alone-validation-ok

TDD Issue Tag Alone Is Valid
    [Documentation]    A test with only ``tdd_issue`` (no ``tdd_issue_<N>`` or
    ...    ``tdd_expected_fail``) should pass normally — the listener should
    ...    not interfere. ``tdd_issue`` alone is a valid tag combination.
    [Tags]    tdd_infrastructure
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    tdd-issue-alone-valid    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-issue-alone-valid-ok

# ===========================================================================
# Robot-side guard tests (tdd_expected_fail_listener.py guards)
# ===========================================================================

TDD Expected Fail Setup Error Guard Prevents Inversion
    [Documentation]    A ``tdd_expected_fail`` test whose setup fails should NOT
    ...    have its result inverted. The setup/teardown error guard should detect
    ...    the setup failure and preserve the original FAIL status.
    [Tags]    tdd_infrastructure    guard
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    setup-error-guard    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-setup-error-guard-ok

TDD Expected Fail Teardown Error Guard Prevents Inversion
    [Documentation]    A ``tdd_expected_fail`` test whose teardown fails should NOT
    ...    be inverted. Even though the body may have passed, the teardown failure
    ...    indicates cleanup issues, so the guard must preserve the FAIL status.
    [Tags]    tdd_infrastructure    guard
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    teardown-error-guard    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-teardown-error-guard-ok

TDD Expected Fail Infrastructure Error Guard Prevents Inversion
    [Documentation]    A ``tdd_expected_fail`` test that fails with a non-assertion
    ...    infrastructure error (e.g., missing keyword) should NOT have its result
    ...    inverted. The non-assertion failure guard should detect the infrastructure
    ...    error pattern and preserve the original FAIL status.
    [Tags]    tdd_infrastructure    guard
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    infra-error-guard    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-infra-error-guard-ok

TDD Expected Fail Dry Run Guard Prevents Inversion
    [Documentation]    A ``tdd_expected_fail`` test run in dry-run mode should NOT
    ...    have its result inverted. The dry-run guard should observe the PASS
    ...    status emitted during keyword validation and leave it untouched.
    [Tags]    tdd_infrastructure    guard
    ${result}=    Run Process    ${PYTHON}    ${HELPER}    dry-run-guard    cwd=${WORKSPACE}
    Log    ${result.stdout}
    Log    ${result.stderr}
    Should Be Equal As Integers    ${result.rc}    0
    Should Contain    ${result.stdout}    tdd-dry-run-guard-ok
