sebastian/comparator
sebastian/comparator compares PHP values for equality with type-aware comparators. Use the Factory to select the right comparator and get helpful ComparisonFailure details when assertions fail—ideal for test suites and tooling.
Strengths:
toArray() results).config(), cache() data).DateTime, DateInterval, and DOMNode, which Laravel frequently uses (e.g., Carbon, scheduled jobs).Gaps:
Carbon, Collection, or Eloquent models (opportunity for extension).composer require sebastian/comparator:^8.2 (dev dependency for tests).json_encode() hacks) with Comparator in critical test files.CarbonComparator).Collection) requires understanding its factory pattern. Start with existing comparators as templates.Illuminate\Support\Collection or Illuminate\Database\Eloquent\Model to ensure comparators handle Laravel’s magic methods (e.g., __toString()) correctly.config(), cache()) that could break with the string key fix?StrictUnifiedDiffOutputBuilder for context lines.assertSame() for objects)? Audit for potential false positives.assertEquals() with Comparator-backed assertions for complex types, leveraging new closure and diff improvements.assertEquals($response->json(), $expected)) with cleaner canonicalized diffs.assertEquals($users->toArray(), $expected)) with preserved string keys.assertEquals($service->process($input), $expected)), including closure-based logic.spl_object_id() issues in model collections (fixed in v8.1.2) and leverage cleaner diffs for nested relationships.DateTime comparisons for scheduled jobs or API timestamps.Illuminate\Support\Collection results with preserved string keys.assertEquals(1, 1)); stick to native assertions.json_encode() hacks, assertSame() overuse).Comparator assertions, focusing on:
// Before
$this->assertEquals(json_encode($actual), json_encode($expected));
// After (v8.2.1)
$comparator = (new Factory)->getComparatorFor($actual, $expected);
$comparator->assertEquals($actual, $expected); // Leverages cleaner diffs and closure support
app/Testing/ComparatorHelper) to wrap Comparator for consistency.use SebastianBergmann\Comparator\Factory;
class ComparatorHelper {
public static function assertEquals($actual, $expected) {
(new Factory)->getComparatorFor($actual, $expected)->assertEquals($actual, $expected);
}
}
CarbonComparator, CollectionComparator).use SebastianBergmann\Comparator\Comparator;
use Closure;
class ClosureComparator extends Comparator {
protected function compare($expected, $actual) {
return $expected instanceof Closure && $actual instanceof Closure
? $expected->__invoke() === $actual->__invoke()
: false;
}
}
composer update sebastian/comparator --dev).use function SebastianBergmann\Comparator\Factory\getComparatorFor;
test('example with closure', function () {
$comparator = getComparatorFor($actualClosure, $expectedClosure);
$comparator->assertEquals($actualClosure, $expectedClosure); // Uses by-value comparison
});
__toString() or custom comparators for Laravel models. Example for Eloquent:
$comparator = (new Factory)->getComparatorFor(
$model1->toArray(),
$model2->toArray()
);
$comparator->assertEquals($model1->toArray(), $model2->toArray()); // Preserves string keys
How can I help you explore Laravel packages today?