Skip to content

Commit

Permalink
Merge pull request #34 from reactphp/some-underflow
Browse files Browse the repository at this point in the history
Reject some() (and any()) if the input array contains not enough items
  • Loading branch information
jsor committed Mar 30, 2016
2 parents bfbfd38 + e2a82ee commit 137f007
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 7 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,9 @@ will be the resolution value of the triggering item.
The returned promise will only reject if *all* items in `$promisesOrValues` are
rejected. The rejection value will be an array of all rejection reasons.

The returned promise will also reject with a `React\Promise\Exception\LengthException`
if `$promisesOrValues` contains 0 items.

#### some()

```php
Expand All @@ -539,6 +542,9 @@ to resolve (that is, when `(count($promisesOrValues) - $howMany) + 1` items
reject). The rejection value will be an array of
`(count($promisesOrValues) - $howMany) + 1` rejection reasons.

The returned promise will also reject with a `React\Promise\Exception\LengthException`
if `$promisesOrValues` contains less items than `$howMany`.

#### map()

```php
Expand Down
7 changes: 7 additions & 0 deletions src/Exception/LengthException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace React\Promise\Exception;

class LengthException extends \LengthException
{
}
19 changes: 16 additions & 3 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,26 @@ function some($promisesOrValues, $howMany)
return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $howMany, $cancellationQueue) {
resolve($promisesOrValues)
->done(function ($array) use ($howMany, $cancellationQueue, $resolve, $reject, $notify) {
if (!is_array($array) || !$array || $howMany < 1) {
if (!is_array($array) || $howMany < 1) {
$resolve([]);
return;
}

$len = count($array);
$toResolve = min($howMany, $len);
$len = count($array);

if ($len < $howMany) {
throw new Exception\LengthException(
sprintf(
'Input array must contain at least %d item%s but contains only %s item%s.',
$howMany,
1 === $howMany ? '' : 's',
$len,
1 === $len ? '' : 's'
)
);
}

$toResolve = $howMany;
$toReject = ($len - $toResolve) + 1;
$values = [];
$reasons = [];
Expand Down
24 changes: 22 additions & 2 deletions tests/FunctionAnyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,38 @@

namespace React\Promise;

use React\Promise\Exception\LengthException;

class FunctionAnyTest extends TestCase
{
/** @test */
public function shouldResolveToNullWithEmptyInputArray()
public function shouldRejectWithLengthExceptionWithEmptyInputArray()
{
$mock = $this->createCallableMock();
$mock
->expects($this->once())
->method('__invoke')
->with($this->identicalTo(null));
->with(
$this->callback(function($exception){
return $exception instanceof LengthException &&
'Input array must contain at least 1 item but contains only 0 items.' === $exception->getMessage();
})
);

any([])
->then($this->expectCallableNever(), $mock);
}

/** @test */
public function shouldResolveToNullWithNonArrayInput()
{
$mock = $this->createCallableMock();
$mock
->expects($this->once())
->method('__invoke')
->with($this->identicalTo(null));

any(null)
->then($mock);
}

Expand Down
46 changes: 44 additions & 2 deletions tests/FunctionSomeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,62 @@

namespace React\Promise;

use React\Promise\Exception\LengthException;

class FunctionSomeTest extends TestCase
{
/** @test */
public function shouldResolveEmptyInput()
public function shouldRejectWithLengthExceptionWithEmptyInputArray()
{
$mock = $this->createCallableMock();
$mock
->expects($this->once())
->method('__invoke')
->with($this->identicalTo([]));
->with(
$this->callback(function($exception){
return $exception instanceof LengthException &&
'Input array must contain at least 1 item but contains only 0 items.' === $exception->getMessage();
})
);

some(
[],
1
)->then($this->expectCallableNever(), $mock);
}

/** @test */
public function shouldRejectWithLengthExceptionWithInputArrayContainingNotEnoughItems()
{
$mock = $this->createCallableMock();
$mock
->expects($this->once())
->method('__invoke')
->with(
$this->callback(function($exception){
return $exception instanceof LengthException &&
'Input array must contain at least 4 items but contains only 3 items.' === $exception->getMessage();
})
);

some(
[1, 2, 3],
4
)->then($this->expectCallableNever(), $mock);
}

/** @test */
public function shouldResolveToEmptyArrayWithNonArrayInput()
{
$mock = $this->createCallableMock();
$mock
->expects($this->once())
->method('__invoke')
->with($this->identicalTo([]));

some(
null,
1
)->then($mock);
}

Expand Down

0 comments on commit 137f007

Please sign in to comment.