sebastianbergmann/comparator · error · ComparisonFailure
Failed asserting that
Error message
Failed asserting that %s matches expected %s.
What it means
NumericComparator compares int/float values within a delta ($delta defaults to 0.1 for its PHPUnit usage). It throws a ComparisonFailure when exactly one side is infinite, either side is NAN, or the absolute difference exceeds the delta. NAN comparisons fail by definition since NAN != NAN.
Solutions
- Check the failure diff: if NAN/INF appears, find where the computation becomes undefined (log of non-positive, division by zero, sqrt of negative) and guard the input
- Add a delta tolerant of floating-point precision: assertEqualsWithDelta($expected, $actual, 1e-9)
- Fix the calculation or update the expected value if the difference is a real regression/feature change
- Convert to exact comparisons on scaled integers or strings when float precision makes equality unstable
Example fix
// before $this->assertEquals(0.3, $a + $b); // 0.30000000000000004 fails // after $this->assertEqualsWithDelta(0.3, $a + $b, 0.000000001);
Defensive patterns
Strategy: validation
Validate before calling
if (is_nan($actual) || is_infinite($actual) || is_nan($expected) || is_infinite($expected)) {
throw new InvalidArgumentException('Cannot compare NAN/INF values');
}
if (abs($actual - $expected) > $tolerance) { /* handle before asserting */ } Type guard
function isComparableNumber(mixed $v): bool { return is_int($v) || (is_float($v) && !is_nan($v) && !is_infinite($v)); } Try / catch
try {
$comparator->assertEquals($expected, $actual, $delta);
} catch (ComparisonFailure $e) {
// inspect exporter output; treat NAN/INF as a computation bug upstream
} Prevention
- Guard math inputs against undefined operations (log of <=0, sqrt of negative, division by zero) before comparing
- Use assertEqualsWithDelta with an explicit precision-appropriate delta instead of relying on the 0.1 default
- Remember NAN fails every comparison including against itself; check is_nan() explicitly
When it happens
Trigger: assertEquals() on numbers where: one value is INF/NAN (e.g. from division by zero, log(0), sqrt(-1)), or abs($actual - $expected) > $delta, e.g. assertEquals(1.0, 1.2) with default or too-tight delta.
Common situations: Comparing floating-point results of math functions that produce NAN/INF (log(0), atanh(>1), 1/0 via intdiv overflow paths); accumulated float precision error exceeding the delta; forgetting that the delta defaults to 0.1 rather than exact equality.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Failed asserting that two values of enumeration
- Failed asserting that two Number objects are equal.
- is not instance of expected class " ".
- Failed asserting that two arrays are equal.
- Failed asserting that closure declared at
AI-assisted analysis of sebastianbergmann/comparator@00837a9d22 (2026-09-15).
Data as JSON: /api/errors/0a462f9786df5853.
Report an issue: GitHub.
Appendix: source
Thrown at src/NumericComparator.php:58
assert(is_numeric($expected));
assert(is_numeric($actual));
if ($this->isInfinite($expected) && $this->isInfinite($actual)) {
if ($expected < 0 && $actual < 0) {
return;
}
if ($expected > 0 && $actual > 0) {
return;
}
}
if (($this->isInfinite($actual) xor $this->isInfinite($expected)) ||
($this->isNan($actual) || $this->isNan($expected)) ||
abs($actual - $expected) > $delta) {
$exporter = $this->exporter();
throw new ComparisonFailure(
$expected,
$actual,
'',
'',
sprintf(
'Failed asserting that %s matches expected %s.',
$exporter->export($actual),
$exporter->export($expected),
),
$this->contextLines(),
);
}
}
private function isInfinite(mixed $value): bool
{
return is_float($value) && is_infinite($value);
}View on GitHub (pinned to 00837a9d22)