1
0
mirror of https://github.com/danog/amp.git synced 2025-01-22 05:11:42 +01:00

add tests

This commit is contained in:
Daniel Lowrey 2015-07-21 17:25:18 -04:00
parent dcab6907c0
commit 33fd20acb3
2 changed files with 191 additions and 7 deletions

View File

@ -224,7 +224,7 @@ function any(array $promises) {
function first(array $promises) {
if (empty($promises)) {
return new Failure(new \LogicException(
"No promises or values provided for first() resolution"
"No promises or values provided"
));
}
@ -244,7 +244,7 @@ function first(array $promises) {
}
if (--$struct->remaining === 0) {
$struct->promisor->fail(new \RuntimeException(
"All promises passed for first() resolution failed"
"All promises failed"
));
}
};
@ -295,7 +295,14 @@ function map(array $promises, callable $functor) {
$struct->remaining--;
try {
$struct->results[$key] = \call_user_func($struct->functor, $result);
} catch (\Throwable $e) {
$struct->remaining = 0;
$struct->promisor->fail($e);
return;
} catch (\Exception $e) {
/**
* @TODO This extra catch block is necessary for PHP5; remove once PHP7 is required
*/
$struct->remaining = 0;
$struct->promisor->fail($e);
return;
@ -312,7 +319,13 @@ function map(array $promises, callable $functor) {
$struct->remaining--;
try {
$struct->results[$key] = \call_user_func($struct->functor, $promise);
} catch (\Throwable $e) {
$struct->remaining = 0;
$struct->promisor->fail($e);
} catch (\Exception $e) {
/**
* @TODO This extra catch block is necessary for PHP5; remove once PHP7 is required
*/
$struct->remaining = 0;
$struct->promisor->fail($e);
}
@ -363,7 +376,14 @@ function filter(array $promises, callable $functor) {
if (\call_user_func($struct->functor, $result)) {
$struct->results[$key] = $result;
}
} catch (\Throwable $e) {
$struct->remaining = 0;
$struct->promisor->fail($e);
return;
} catch (\Exception $e) {
/**
* @TODO This extra catch block is necessary for PHP5; remove once PHP7 is required
*/
$struct->remaining = 0;
$struct->promisor->fail($e);
return;
@ -382,7 +402,13 @@ function filter(array $promises, callable $functor) {
if (\call_user_func($struct->functor, $promise)) {
$struct->results[$key] = $promise;
}
} catch (\Throwable $e) {
$struct->remaining = 0;
$struct->promisor->fail($e);
} catch (\Exception $e) {
/**
* @TODO This extra catch block is necessary for PHP5; remove once PHP7 is required
*/
$struct->remaining = 0;
$struct->promisor->fail($e);
}
@ -403,10 +429,15 @@ function filter(array $promises, callable $functor) {
* @return \Amp\Promise
*/
function pipe($promise, callable $functor) {
if (!($promise instanceof Promise)) {
if (!$promise instanceof Promise) {
try {
return new Success(\call_user_func($functor, $promise));
} catch (\Throwable $e) {
return new Failure($e);
} catch (\Exception $e) {
/**
* @TODO This extra catch block is necessary for PHP5; remove once PHP7 is required
*/
return new Failure($e);
}
}
@ -419,7 +450,12 @@ function pipe($promise, callable $functor) {
}
try {
$promisor->succeed(\call_user_func($functor, $result));
} catch (\Throwable $error) {
$promisor->fail($error);
} catch (\Exception $error) {
/**
* @TODO This extra catch block is necessary for PHP5; remove once PHP7 is required
*/
$promisor->fail($error);
}
});
@ -468,10 +504,11 @@ function timeout(Promise $promise, $msTimeout, Reactor $reactor = null) {
"Promise resolution timed out"
));
}, $msTimeout);
$promise->when(function($error = null, $result = null) use ($reactor, $promisor, $watcherId, $resolved) {
$promise->when(function($error = null, $result = null) use ($reactor, $promisor, $watcherId, &$resolved) {
if ($resolved) {
return;
}
$resolved = true;
$reactor->cancel($watcherId);
if ($error) {
$promisor->fail($error);

View File

@ -10,7 +10,7 @@ use Amp\PromiseStream;
class FunctionsTest extends \PHPUnit_Framework_TestCase {
public function testPipe() {
public function testPipeWrapsRawValue() {
$invoked = 0;
$promise = \Amp\pipe(21, function($r) { return $r * 2; });
$promise->when(function($e, $r) use (&$invoked) {
@ -20,6 +20,21 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
$this->assertSame(1, $invoked);
}
public function testPipeTransformsEventualPromiseResult() {
$result = 0;
(new NativeReactor)->run(function ($reactor) use (&$result) {
$promisor = new Deferred;
$reactor->once(function () use ($promisor) {
$promisor->succeed("woot");
}, 10);
$promise = $promisor->promise();
$result = (yield \Amp\pipe($promise, "strtoupper"));
});
$this->assertSame("WOOT", $result);
}
public function testPipeAbortsIfOriginalPromiseFails() {
$invoked = 0;
$failure = new Failure(new \RuntimeException);
@ -31,7 +46,7 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
$this->assertSame(1, $invoked);
}
public function testPipeAbortsIfFunctorThrows() {
public function testPipeAbortsIfFunctorThrowsOnRawValue() {
$invoked = 0;
$promise = \Amp\pipe(42, function(){ throw new \RuntimeException; });
$promise->when(function($e, $r) use (&$invoked) {
@ -41,6 +56,16 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
$this->assertSame(1, $invoked);
}
public function testPipeAbortsIfFunctorThrows() {
$invoked = 0;
$promise = \Amp\pipe(new Success(42), function(){ throw new \RuntimeException; });
$promise->when(function($e, $r) use (&$invoked) {
$invoked++;
$this->assertInstanceOf("RuntimeException", $e);
});
$this->assertSame(1, $invoked);
}
public function testAllResolutionWhenNoPromiseInstancesCombined() {
$promises = [null, 1, 2, true];
\Amp\all($promises)->when(function($e, $r) {
@ -136,7 +161,7 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
$this->assertSame(['r1' => 42, 'r3' => 40], $results);
});
}
public function testSomeFailsImmediatelyOnEmptyPromiseArrayInput() {
$promise = \Amp\some([]);
$this->assertInstanceOf("Amp\Failure", $promise);
@ -163,6 +188,76 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
});
}
public function testFirstFailsImmediatelyOnEmptyPromiseArrayInput() {
$promise = \Amp\first([]);
$this->assertInstanceOf("Amp\Failure", $promise);
$error = null;
$result = null;
$promise->when(function($e, $r) use (&$error, &$result) {
$error = $e;
$result = $r;
});
$this->assertNull($result);
$this->assertInstanceOf("\LogicException", $error);
$this->assertSame("No promises or values provided", $error->getMessage());
}
public function testFirst() {
$resolutionCount = 0;
$result = 0;
(new NativeReactor)->run(function ($reactor) use (&$resolutionCount, &$result) {
$p1 = new Deferred;
$reactor->once(function () use ($p1, &$resolutionCount) {
$p1->succeed(1);
$resolutionCount++;
}, 10);
$p2 = new Deferred;
$reactor->once(function () use ($p2, &$resolutionCount) {
$p2->succeed(2);
$resolutionCount++;
}, 20);
$p3 = new Deferred;
$reactor->once(function () use ($p3, &$resolutionCount) {
$p3->succeed(3);
$resolutionCount++;
}, 30);
$promises = [$p1->promise(), $p2->promise(), $p3->promise()];
$allPromise = \Amp\all($promises, $reactor);
$allPromise->when([$reactor, "stop"]);
$result = (yield \Amp\first($promises, $reactor));
});
$this->assertSame(3, $resolutionCount);
$this->assertSame(1, $result);
}
public function testNonPromiseValueImmediatelyResolvesFirstCombinator() {
$result = 0;
(new NativeReactor)->run(function ($reactor) use (&$result) {
$p1 = 42;
$p2 = (new Deferred)->promise();
$result = (yield \Amp\first([$p1, $p2], $reactor));
});
$this->assertSame(42, $result);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage All promises failed
*/
public function testFirstFailsIfAllPromisesFail() {
(new NativeReactor)->run(function ($reactor) use (&$result) {
$e1 = new \Exception("foo");
$e2 = new \Exception("bar");
$promises = [new Failure($e1), new Failure($e2)];
yield \Amp\first($promises, $reactor);
});
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Promise resolution timed out
@ -174,6 +269,58 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
});
}
public function testTimeoutOnSuccess() {
$invoked = false;
(new NativeReactor)->run(function ($reactor) use (&$invoked) {
$promisor = new Deferred;
$reactor->once(function () use ($promisor) {
$promisor->succeed(42);
}, 10);
$result = (yield \Amp\timeout($promisor->promise(), 10000, $reactor));
$this->assertSame(42, $result);
$invoked = true;
});
$this->assertTrue($invoked);
}
/**
* @expectedException RuntimeException
* @expectedExceptionMessage nothing that is worth knowing can be taught
*/
public function testTimeoutOnFailure() {
(new NativeReactor)->run(function ($reactor) {
$promisor = new Deferred;
$reactor->once(function () use ($promisor) {
$promisor->fail(new \RuntimeException(
"nothing that is worth knowing can be taught"
));
}, 10);
$result = (yield \Amp\timeout($promisor->promise(), 10000, $reactor));
});
}
public function testTimeoutIgnoresResultIfAlreadyComplete() {
$invoked = false;
(new NativeReactor)->run(function ($reactor) use (&$invoked) {
$promisor = new Deferred;
$reactor->once(function () use ($promisor) {
$promisor->succeed(42);
}, 100);
try {
$result = (yield \Amp\timeout($promisor->promise(), 10, $reactor));
} catch (\RuntimeException $e) {
// ignore this
}
yield $promisor->promise();
$invoked = true;
});
$this->assertTrue($invoked);
}
public function testAllCombinatorResolution() {
$invoked = 0;
(new NativeReactor)->run(function($reactor) use (&$invoked) {