Add more comprehensive set assertion rewrites (#11469)

Fixes #10617
This commit is contained in:
Reagan Lee 2023-10-02 14:37:52 -07:00 committed by GitHub
parent d015bc1b8f
commit 9bbfe995ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 131 additions and 47 deletions

View File

@ -0,0 +1,2 @@
Added more comprehensive set assertion rewrites for comparisons other than equality ``==``, with
the following operations now providing better failure messages: ``!=``, ``<=``, ``>=``, ``<``, and ``>``.

View File

@ -193,6 +193,22 @@ def assertrepr_compare(
elif op == "not in":
if istext(left) and istext(right):
explanation = _notin_text(left, right, verbose)
elif op == "!=":
if isset(left) and isset(right):
explanation = ["Both sets are equal"]
elif op == ">=":
if isset(left) and isset(right):
explanation = _compare_gte_set(left, right, verbose)
elif op == "<=":
if isset(left) and isset(right):
explanation = _compare_lte_set(left, right, verbose)
elif op == ">":
if isset(left) and isset(right):
explanation = _compare_gt_set(left, right, verbose)
elif op == "<":
if isset(left) and isset(right):
explanation = _compare_lt_set(left, right, verbose)
except outcomes.Exit:
raise
except Exception:
@ -392,15 +408,49 @@ def _compare_eq_set(
left: AbstractSet[Any], right: AbstractSet[Any], verbose: int = 0
) -> List[str]:
explanation = []
diff_left = left - right
diff_right = right - left
if diff_left:
explanation.append("Extra items in the left set:")
for item in diff_left:
explanation.append(saferepr(item))
if diff_right:
explanation.append("Extra items in the right set:")
for item in diff_right:
explanation.extend(_set_one_sided_diff("left", left, right))
explanation.extend(_set_one_sided_diff("right", right, left))
return explanation
def _compare_gt_set(
left: AbstractSet[Any], right: AbstractSet[Any], verbose: int = 0
) -> List[str]:
explanation = _compare_gte_set(left, right, verbose)
if not explanation:
return ["Both sets are equal"]
return explanation
def _compare_lt_set(
left: AbstractSet[Any], right: AbstractSet[Any], verbose: int = 0
) -> List[str]:
explanation = _compare_lte_set(left, right, verbose)
if not explanation:
return ["Both sets are equal"]
return explanation
def _compare_gte_set(
left: AbstractSet[Any], right: AbstractSet[Any], verbose: int = 0
) -> List[str]:
return _set_one_sided_diff("right", right, left)
def _compare_lte_set(
left: AbstractSet[Any], right: AbstractSet[Any], verbose: int = 0
) -> List[str]:
return _set_one_sided_diff("left", left, right)
def _set_one_sided_diff(
posn: str, set1: AbstractSet[Any], set2: AbstractSet[Any]
) -> List[str]:
explanation = []
diff = set1 - set2
if diff:
explanation.append(f"Extra items in the {posn} set:")
for item in diff:
explanation.append(saferepr(item))
return explanation

View File

@ -1345,7 +1345,61 @@ def test_reprcompare_whitespaces() -> None:
]
def test_pytest_assertrepr_compare_integration(pytester: Pytester) -> None:
class TestSetAssertions:
@pytest.mark.parametrize("op", [">=", ">", "<=", "<", "=="])
def test_set_extra_item(self, op, pytester: Pytester) -> None:
pytester.makepyfile(
f"""
def test_hello():
x = set("hello x")
y = set("hello y")
assert x {op} y
"""
)
result = pytester.runpytest()
result.stdout.fnmatch_lines(
[
"*def test_hello():*",
f"*assert x {op} y*",
]
)
if op in [">=", ">", "=="]:
result.stdout.fnmatch_lines(
[
"*E*Extra items in the right set:*",
"*E*'y'",
]
)
if op in ["<=", "<", "=="]:
result.stdout.fnmatch_lines(
[
"*E*Extra items in the left set:*",
"*E*'x'",
]
)
@pytest.mark.parametrize("op", [">", "<", "!="])
def test_set_proper_superset_equal(self, pytester: Pytester, op) -> None:
pytester.makepyfile(
f"""
def test_hello():
x = set([1, 2, 3])
y = x.copy()
assert x {op} y
"""
)
result = pytester.runpytest()
result.stdout.fnmatch_lines(
[
"*def test_hello():*",
f"*assert x {op} y*",
"*E*Both sets are equal*",
]
)
def test_pytest_assertrepr_compare_integration(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
def test_hello():
@ -1367,28 +1421,6 @@ def test_pytest_assertrepr_compare_integration(pytester: Pytester) -> None:
)
def test_sequence_comparison_uses_repr(pytester: Pytester) -> None:
pytester.makepyfile(
"""
def test_hello():
x = set("hello x")
y = set("hello y")
assert x == y
"""
)
result = pytester.runpytest()
result.stdout.fnmatch_lines(
[
"*def test_hello():*",
"*assert x == y*",
"*E*Extra items*left*",
"*E*'x'*",
"*E*Extra items*right*",
"*E*'y'*",
]
)
def test_assertrepr_loaded_per_dir(pytester: Pytester) -> None:
pytester.makepyfile(test_base=["def test_base(): assert 1 == 2"])
a = pytester.mkdir("a")