Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -744,35 +744,27 @@ def _get_match(self, check_values, record, tolerance=None) -> bool:
if record is None and self.accept_none:
record = 0
match_boolean = True

# abs() so the tolerance margin widens the bound outward for negative expected values too.
def _margin(expected):
return abs(expected) * tolerance if tolerance is not None else 0

if "geq_to" in check_values:
if tolerance is not None:
match_boolean = record >= check_values["geq_to"] * (1 - tolerance)
else:
match_boolean = record >= check_values["geq_to"]
match_boolean = record >= check_values["geq_to"] - _margin(check_values["geq_to"])
elif "greater_than" in check_values:
if tolerance is not None:
match_boolean = record > check_values["greater_than"] * (1 - tolerance)
else:
match_boolean = record > check_values["greater_than"]
match_boolean = record > check_values["greater_than"] - _margin(check_values["greater_than"])
if "leq_to" in check_values:
if tolerance is not None:
match_boolean = record <= check_values["leq_to"] * (1 + tolerance) and match_boolean
else:
match_boolean = record <= check_values["leq_to"] and match_boolean
match_boolean = (
record <= check_values["leq_to"] + _margin(check_values["leq_to"]) and match_boolean
)
elif "less_than" in check_values:
if tolerance is not None:
match_boolean = record < check_values["less_than"] * (1 + tolerance) and match_boolean
else:
match_boolean = record < check_values["less_than"] and match_boolean
match_boolean = (
record < check_values["less_than"] + _margin(check_values["less_than"]) and match_boolean
)
if "equal_to" in check_values:
if tolerance is not None:
match_boolean = (
check_values["equal_to"] * (1 - tolerance)
<= record
<= check_values["equal_to"] * (1 + tolerance)
) and match_boolean
else:
match_boolean = record == check_values["equal_to"] and match_boolean
expected = check_values["equal_to"]
margin = _margin(expected)
match_boolean = (expected - margin <= record <= expected + margin) and match_boolean
return match_boolean

def _column_mapping_validation(self, check, check_values):
Expand Down
30 changes: 30 additions & 0 deletions providers/common/sql/tests/unit/common/sql/operators/test_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -1684,6 +1684,36 @@ def test_accepted_range_geq_leq(self):
assert r.expected == ">=1, <=100"
assert r.params == {"geq_to": 1, "leq_to": 100, "accept_none": True}

@pytest.mark.parametrize(
("check_values", "record", "tolerance", "expected"),
[
# Negative thresholds: tolerance widens the bound outward, so a record equal to
# the threshold passes.
({"geq_to": -1000}, -1000, 0.1, True),
({"geq_to": -1000}, -1100, 0.1, True),
({"geq_to": -1000}, -1101, 0.1, False),
({"greater_than": -1000}, -1050, 0.1, True),
({"greater_than": -1000}, -1100, 0.1, False), # strict: equal to the widened bound fails
({"leq_to": -10}, -10, 0.1, True),
({"less_than": -10}, -11, 0.1, True),
({"equal_to": -100}, -100, 0.1, True),
({"equal_to": -100}, -110, 0.1, True),
({"equal_to": -100}, -111, 0.1, False),
({"geq_to": -100, "leq_to": -50}, -75, 0.1, True),
# Positive thresholds keep their existing bounds.
({"geq_to": 1000}, 900, 0.1, True),
({"geq_to": 1000}, 899, 0.1, False),
({"equal_to": 100}, 110, 0.1, True),
({"equal_to": 100}, 111, 0.1, False),
# No tolerance: exact bounds.
({"geq_to": 10}, 10, None, True),
({"equal_to": 5}, 6, None, False),
],
)
def test_get_match_tolerance_handles_negative_thresholds(self, check_values, record, tolerance, expected):
op = self._make_operator({"col": {"min": {"geq_to": 1}}})
assert op._get_match(check_values, record, tolerance) == expected

def test_multiple_checks_correct_names_and_order(self):
op = self._make_operator(
{
Expand Down