Skip to content

Commit

Permalink
feat: add toBeOneOf() expectation
Browse files Browse the repository at this point in the history
  • Loading branch information
dshafik committed Oct 6, 2024
1 parent 1e0bb88 commit d87bd72
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 0 deletions.
30 changes: 30 additions & 0 deletions src/Expectation.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use Pest\Support\ExpectationPipeline;
use Pest\Support\Reflection;
use PHPUnit\Architecture\Elements\ObjectDescription;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\ExpectationFailedException;
use ReflectionEnum;
use ReflectionMethod;
Expand Down Expand Up @@ -324,6 +325,35 @@ public function when(callable|bool $condition, callable $callback): self
return $this;
}

public function toBeOneOf(Closure ...$tests): self
{
if ($tests === []) {
return $this;
}

$matches = [];
$exceptions = [];

foreach ($tests as $key => $test) {
try {
$test(new Expectation($this->value));
$matches[] = $key;
} catch (AssertionFailedError) {
$exceptions[] = $key;
}
}

if (count($matches) === 1) {
return $this;
}

if (count($matches) > 1) {
throw new ExpectationFailedException('Failed asserting value matches exactly one expectation (matches: '.implode(', ', $matches).').');
}

throw new ExpectationFailedException('Failed asserting value matches any expectations.');
}

/**
* Dynamically calls methods on the class or creates a new higher order expectation.
*
Expand Down
40 changes: 40 additions & 0 deletions tests/Features/Expect/toBeOneOf.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

use PHPUnit\Framework\ExpectationFailedException;

expect(true)->toBeTrue()->and(false)->toBeFalse();

test('risky with no assertions', function () {
expect(1)->toBeOneOf();
})->throwsNoExceptions();

test('to be one of', function () {
expect(1)->toBeOneOf(fn ($e) => $e->toBe(1), fn ($e) => $e->toBe(2), fn ($e) => $e->toBe(3));
});

test('it does not short-circuit', function () {
$executed = 0;
expect(1)->toBeOneOf(function ($e) use (&$executed) {
$executed++;

return $e->toBe(1);
}, function ($e) use (&$executed) {
$executed++;

return $e->toBe(2);
}, function ($e) use (&$executed) {
$executed++;

return $e->toBe(3);
});

expect($executed)->toBe(3);
});

test('failure with multiple matches', function () {
expect(1)->toBeOneOf(fn ($e) => $e->toBe(1), fn ($e) => $e->toBe(1));
})->throws(ExpectationFailedException::class, 'Failed asserting value matches exactly one expectation (matches: 0, 1).');

test('failure with no matches', function () {
expect(1)->toBeOneOf(fn ($e) => $e->toBe(2), fn ($e) => $e->toBe(2));
})->throws(ExpectationFailedException::class, 'Failed asserting value matches any expectations.');

0 comments on commit d87bd72

Please sign in to comment.