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

  1. 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
  2. Add a delta tolerant of floating-point precision: assertEqualsWithDelta($expected, $actual, 1e-9)
  3. Fix the calculation or update the expected value if the difference is a real regression/feature change
  4. 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

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


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)