Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions src/falsegreen_robot/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,15 +263,20 @@ def is_verification(keyword, args, local_keywords=None, extra_verify=None):
key, sep, val = (a or "").partition("=")
if sep and _norm(key) == "expected_status":
return _norm(val) not in _EXPECTED_STATUS_OFF and bool(val.strip())
# Run Keyword And Continue On Failure / And Warn On Failure <kw> *args -
# the soft-assert wrappers: the wrapped keyword still runs and is verified, the
# wrapper only changes how a failure is reported (continue / warn). It is an
# oracle exactly when the wrapped keyword is one, so recurse on the inner call.
if n in ("run keyword and continue on failure", "run keyword and warn on failure"):
# Run Keyword And Continue On Failure <kw> *args - a soft-assert wrapper:
# the wrapped keyword still runs and a failure is recorded, so the test FAILS at
# the end. It is an oracle exactly when the wrapped keyword is one, so recurse.
if n == "run keyword and continue on failure":
inner = list(args or ())
if inner:
return is_verification(inner[0], inner[1:], local_keywords, extra_verify)
return False
# Run Keyword And Warn On Failure <kw> *args - a failure only logs a WARN
# and the test stays green (BuiltIn semantics). The wrapped assertion can never
# reprove the test, so this is NOT an oracle regardless of the inner keyword -
# same swallow problem as Run Keyword And Ignore Error (#88).
if n == "run keyword and warn on failure":
return False
# Run Keywords A AND B AND Should Be Equal ... — a chain that
# runs each keyword in sequence. The verification can be any segment, so split
# on the AND separator and check each segment's first token as a nested call.
Expand Down
28 changes: 25 additions & 3 deletions tests/test_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2275,14 +2275,36 @@ def test_no_r2_continue_on_failure_around_assertion(tmp_path):
assert "R2" not in codes(tmp_path, body)


def test_no_r2_warn_on_failure_around_assertion(tmp_path):
# The Warn On Failure variant is the same soft-assert wrapper.
def test_r2_warn_on_failure_around_assertion_is_hollow(tmp_path):
# #88: Warn On Failure only logs a WARN, the test stays green - the wrapped
# assertion cannot reprove the test, so the verifier keyword is hollow (R2).
body = """\
*** Keywords ***
Verify X
Run Keyword And Warn On Failure Should Be Equal ${a} ${b}
"""
assert "R2" not in codes(tmp_path, body)
assert "R2" in codes(tmp_path, body)


# #88: Warn On Failure is not an oracle (the failure only logs a WARN); Continue
# On Failure still fails the test at the end and remains a valid oracle.
def test_warn_on_failure_is_not_an_oracle_c2b(tmp_path):
body = """\
*** Test Cases ***
Falso Verde
Run Keyword And Warn On Failure Should Be Equal ${1} ${2}
"""
assert "C2b" in codes(tmp_path, body)


def test_continue_on_failure_stays_an_oracle(tmp_path):
body = """\
*** Test Cases ***
Soft Assert
Continue On Failure
Run Keyword And Continue On Failure Should Be Equal ${1} ${2}
"""
assert "C2b" not in codes(tmp_path, body)


# FP-3 (C9b): expected_status=any with a manual status assert on the next line.
Expand Down
Loading