1
0
mirror of https://github.com/danog/amp.git synced 2025-01-21 21:01:16 +01:00

Update tests and remove unused tests

This commit is contained in:
Aaron Piotrowski 2016-07-19 00:05:40 -05:00
parent dad93a6da0
commit 5a06b1cdc1
18 changed files with 26 additions and 2327 deletions

View File

@ -1,12 +0,0 @@
<phpunit bootstrap="./test/bootstrap.php" colors="true">
<testsuites>
<testsuite name="Tests">
<directory>./test</directory>
</testsuite>
</testsuites>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory>./lib</directory>
</whitelist>
</filter>
</phpunit>

View File

@ -1,9 +0,0 @@
<?php
namespace Amp\Test;
abstract class BaseTest extends \PHPUnit_Framework_TestCase {
protected function setUp() {
\Amp\reactor($assign = new \Amp\NativeReactor);
}
}

View File

@ -1,61 +0,0 @@
<?php
namespace Amp\Test;
use Amp\EvReactor;
class EvReactorTest extends ReactorTest {
protected function setUp() {
if (extension_loaded("ev")) {
\Amp\reactor($assign = new EvReactor);
} else {
$this->markTestSkipped(
"ev extension not loaded"
);
}
}
public function testGetLoop() {
$result = \Amp\reactor()->getLoop();
$this->assertInstanceOf("EvLoop", $result);
}
/**
* We take care to cancel the signal watcher because Ev spazzes if
* multiple watchers exist for the same signal in different loops
*/
public function testOnSignalWatcherKeepAliveRunResult() {
if (!\extension_loaded("pcntl")) {
$this->markTestSkipped("ext/pcntl required to test onSignal() registration");
}
$watcherId = null;
\Amp\run(function () use (&$watcherId) {
$watcherId = \Amp\onSignal(SIGUSR1, function () {
// empty
}, $options = ["keep_alive" => false]);
});
\Amp\cancel($watcherId);
}
public function testImmediateCoroutineResolutionError() {
if (\extension_loaded("xdebug")) {
$this->markTestSkipped(
"Cannot run this test with xdebug enabled: it causes zend_mm_heap corrupted"
);
} else {
parent::testImmediateCoroutineResolutionError();
}
}
public function testOnErrorFailure() {
if (\extension_loaded("xdebug")) {
$this->markTestSkipped(
"Cannot run this test with xdebug enabled: it causes zend_mm_heap corrupted"
);
} else {
parent::testImmediateCoroutineResolutionError();
}
}
}

View File

@ -1,905 +0,0 @@
<?php
namespace Amp\Test;
use Amp\CombinatorException;
use Amp\NativeReactor;
use Amp\Success;
use Amp\Failure;
use Amp\Deferred;
use Amp\PromiseStream;
use Amp\Pause;
use Amp\CoroutineResult;
class FunctionsTest extends \PHPUnit_Framework_TestCase {
protected function setUp() {
\Amp\reactor($assign = new NativeReactor);
}
public function testMap() {
$promises = ["test1", new Success("test2"), new Success("test3")];
$functor = "strtoupper";
$promise = \Amp\map($promises, $functor);
$error = null;
$result = null;
$promise->when(function ($e, $r) use (&$error, &$result) {
$error = $e;
$result = $r;
});
$this->assertNull($error);
$this->assertSame(["TEST1", "TEST2", "TEST3"], $result);
}
public function testMapReturnsEmptySuccessOnEmptyInput() {
$promise = \Amp\map([], function () {});
$this->assertInstanceOf('Amp\Success', $promise);
$error = null;
$result = null;
$promise->when(function ($e, $r) use (&$error, &$result) {
$error = $e;
$result = $r;
});
$this->assertNull($error);
$this->assertSame([], $result);
}
/**
* @expectedException Exception
* @expectedExceptionMessage hulk smash
*/
public function testMapFailsIfFunctorThrowsOnUnwrappedValue() {
\Amp\run(function () {
yield \Amp\map(["test"], function () { throw new \Exception("hulk smash"); });
});
}
/**
* @expectedException Exception
* @expectedExceptionMessage hulk smash
*/
public function testMapFailsIfFunctorThrowsOnResolvedValue() {
\Amp\run(function () {
$promises = [new Success("test")];
yield \Amp\map($promises, function () { throw new \Exception("hulk smash"); });
});
}
public function testMapFailsIfAnyPromiseFails() {
$e = new \RuntimeException(
"true progress is to know more, and be more, and to do more"
);
$promise = \Amp\map([new Failure($e)], function () {});
$error = null;
$result = null;
$promise->when(function ($e, $r) use (&$error, &$result) {
$error = $e;
$result = $r;
});
$this->assertSame($e, $error);
$this->assertNull($result);
}
public function testMapIgnoresFurtherResultsOnceFailed() {
$completed = false;
\Amp\run(function () use (&$completed) {
$p1 = new Deferred;
\Amp\once(function () use ($p1) {
$p1->succeed("woot");
}, 50);
$e = new \RuntimeException(
"true progress is to know more, and be more, and to do more"
);
$p2 = new Deferred;
\Amp\once(function () use ($p2, $e) {
$p2->fail($e);
}, 10);
$toMap = \Amp\promises([$p1, $p2]);
try {
yield \Amp\map($toMap, "strtoupper");
$this->fail("this line should not be reached");
} catch (\RuntimeException $error) {
$this->assertSame($e, $error);
}
yield $p1->promise();
$completed = true;
});
$this->assertTrue($completed);
}
public function testFilter() {
$promises = ["test1", new Success("test2"), new Success("test2"), "test2"];
$functor = function ($el) { return $el === "test2"; };
$promise = \Amp\filter($promises, $functor);
$error = null;
$result = null;
$promise->when(function ($e, $r) use (&$error, &$result) {
$error = $e;
$result = $r;
});
$this->assertNull($error);
$this->assertSame([1=>"test2", 2=>"test2", 3=>"test2"], $result);
}
public function testFilterUsesBoolComparisonOnUnspecifiedFunctor() {
$promises = ["test1", new Success, null, false, 0, new Success("test2"), new Success(0), new Success(false) ];
$promise = \Amp\filter($promises);
$error = null;
$result = null;
$promise->when(function ($e, $r) use (&$error, &$result) {
$error = $e;
$result = $r;
});
$this->assertNull($error);
$this->assertSame([0=>"test1", 5=>"test2"], $result);
}
public function testFilter2() {
$promises = ["test1", "test2", new Success("test2"), new Success("test2")];
$functor = function ($el) { return $el === "test2"; };
$promise = \Amp\filter($promises, $functor);
$error = null;
$result = null;
$promise->when(function ($e, $r) use (&$error, &$result) {
$error = $e;
$result = $r;
});
$this->assertNull($error);
$this->assertSame([1=>"test2", 2=>"test2", 3=>"test2"], $result);
}
public function testFilterReturnsEmptySuccessOnEmptyInput() {
$promise = \Amp\filter([], function () {});
$this->assertInstanceOf('Amp\Success', $promise);
$error = null;
$result = null;
$promise->when(function ($e, $r) use (&$error, &$result) {
$error = $e;
$result = $r;
});
$this->assertNull($error);
$this->assertSame([], $result);
}
/**
* @expectedException Exception
* @expectedExceptionMessage hulk smash
*/
public function testFilterFailsIfFunctorThrowsOnUnwrappedValue() {
\Amp\run(function () {
yield \Amp\filter(["test"], function () { throw new \Exception("hulk smash"); });
});
}
/**
* @expectedException Exception
* @expectedExceptionMessage hulk smash
*/
public function testFilterFailsIfFunctorThrowsOnResolvedValue() {
\Amp\run(function () {
$promises = [new Success("test")];
yield \Amp\filter($promises, function () { throw new \Exception("hulk smash"); });
});
}
public function testFilterFailsIfAnyPromiseFails() {
$e = new \RuntimeException(
"true progress is to know more, and be more, and to do more"
);
$promise = \Amp\filter([new Failure($e)], function () {});
$error = null;
$result = null;
$promise->when(function ($e, $r) use (&$error, &$result) {
$error = $e;
$result = $r;
});
$this->assertSame($e, $error);
$this->assertNull($result);
}
public function testFilterIgnoresFurtherResultsOnceFailed() {
$completed = false;
\Amp\run(function () use (&$completed) {
$p1 = new Deferred;
$p2 = new Deferred;
$e = new \RuntimeException(
"true progress is to know more, and be more, and to do more"
);
\Amp\once(function () use ($p1, $p2, $e) {
$p2->fail($e);
\Amp\immediately(function () use ($p1) {
$p1->succeed("woot");
});
}, 10);
$toMap = \Amp\promises([$p1, $p2]);
$functor = function () { return true; };
try {
yield \Amp\filter($toMap, $functor);
$this->fail("this line should not be reached");
} catch (\RuntimeException $error) {
$this->assertSame($e, $error);
}
yield $p1->promise();
$completed = true;
});
$this->assertTrue($completed);
}
public function testPipeWrapsRawValue() {
$invoked = 0;
$promise = \Amp\pipe(21, function ($r) { return $r * 2; });
$promise->when(function ($e, $r) use (&$invoked) {
$invoked++;
$this->assertSame(42, $r);
});
$this->assertSame(1, $invoked);
}
public function testPipeTransformsEventualPromiseResult() {
$result = 0;
\Amp\run(function () use (&$result) {
$promisor = new Deferred;
\Amp\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);
$promise = \Amp\pipe($failure, function (){});
$promise->when(function ($e, $r) use (&$invoked) {
$invoked++;
$this->assertInstanceOf("RuntimeException", $e);
});
$this->assertSame(1, $invoked);
}
public function testPipeAbortsIfFunctorThrowsOnRawValue() {
$invoked = 0;
$promise = \Amp\pipe(42, function (){ throw new \RuntimeException; });
$promise->when(function ($e, $r) use (&$invoked) {
$invoked++;
$this->assertInstanceOf("RuntimeException", $e);
});
$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 testSomeResolutionWhenAllPromisesFail() {
$ex1 = new \RuntimeException("1");
$ex2 = new \RuntimeException("2");
$promises = [new Failure($ex1), new Failure($ex2)];
\Amp\some($promises)->when(function ($e, $r) use ($ex1, $ex2) {
$this->assertNull($r);
$this->assertInstanceOf(CombinatorException::class, $e);
$this->assertSame($e->getExceptions()[0], $ex1);
$this->assertSame($e->getExceptions()[1], $ex2);
});
}
public function testAllResolutionWhenNoPromiseInstancesCombined() {
$promises = [null, 1, 2, true];
\Amp\all($promises)->when(function ($e, $r) {
list($a, $b, $c, $d) = $r;
$this->assertNull($a);
$this->assertSame(1, $b);
$this->assertSame(2, $c);
$this->assertSame(true, $d);
});
}
public function testSomeResolutionWhenNoPromiseInstancesCombined() {
$promises = [null, 1, 2, true];
\Amp\some($promises)->when(function ($e, $r) {
list($errors, $results) = $r;
list($a, $b, $c, $d) = $results;
$this->assertNull($a);
$this->assertSame(1, $b);
$this->assertSame(2, $c);
$this->assertSame(true, $d);
});
}
public function testAnyResolutionWhenNoPromiseInstancesCombined() {
$promises = [null, 1, 2, true];
\Amp\any($promises)->when(function ($e, $r) {
list($errors, $results) = $r;
list($a, $b, $c, $d) = $results;
$this->assertNull($a);
$this->assertSame(1, $b);
$this->assertSame(2, $c);
$this->assertSame(true, $d);
});
}
public function testAnyReturnsImmediatelyOnEmptyPromiseArray() {
$promise = \Amp\any([]);
$this->assertInstanceOf('Amp\Success', $promise);
$error = null;
$result = null;
$promise->when(function ($e, $r) use (&$error, &$result) {
$error = $e;
$result = $r;
});
$this->assertNull($error);
$this->assertSame([[], []], $result);
}
public function testAllResolvesWithArrayOfResults() {
\Amp\all(['r1' => 42, 'r2' => new Success(41)])->when(function ($error, $result) {
$expected = ['r1' => 42, 'r2' => 41];
$this->assertSame($expected, $result);
});
}
public function testAllReturnsImmediatelyOnEmptyPromiseArray() {
$promise = \Amp\all([]);
$this->assertInstanceOf('Amp\Success', $promise);
$error = null;
$result = null;
$promise->when(function ($e, $r) use (&$error, &$result) {
$error = $e;
$result = $r;
});
$this->assertNull($error);
$this->assertSame([], $result);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage zanzibar
*/
public function testAllThrowsIfAnyIndividualPromiseFails() {
$exception = new \RuntimeException('zanzibar');
\Amp\all([
'r1' => new Success(42),
'r2' => new Failure($exception),
'r3' => new Success(40),
])->when(function (\Exception $error) {
throw $error;
});
}
public function testSomeReturnsArrayOfErrorsAndResults() {
$exception = new \RuntimeException('zanzibar');
\Amp\some([
'r1' => new Success(42),
'r2' => new Failure($exception),
'r3' => new Success(40),
])->when(function ($error, $result) use ($exception) {
$this->assertNull($error);
list($errors, $results) = $result;
$this->assertSame(['r2' => $exception], $errors);
$this->assertSame(['r1' => 42, 'r3' => 40], $results);
});
}
public function testSomeFailsImmediatelyOnEmptyPromiseArrayInput() {
$promise = \Amp\some([]);
$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 for resolution", $error->getMessage());
}
/**
* @expectedException \Amp\CombinatorException
*/
public function testSomeThrowsIfNoPromisesResolveSuccessfully() {
\Amp\some([
'r1' => new Failure(new \RuntimeException),
'r2' => new Failure(new \RuntimeException),
])->when(function ($error) {
throw $error;
});
}
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;
\Amp\run(function () use (&$resolutionCount, &$result) {
$p1 = new Deferred;
\Amp\once(function () use ($p1, &$resolutionCount) {
$p1->succeed(1);
$resolutionCount++;
}, 10);
$p2 = new Deferred;
\Amp\once(function () use ($p2, &$resolutionCount) {
$p2->succeed(2);
$resolutionCount++;
}, 20);
$p3 = new Deferred;
\Amp\once(function () use ($p3, &$resolutionCount) {
$p3->succeed(3);
$resolutionCount++;
}, 30);
$promises = [$p1->promise(), $p2->promise(), $p3->promise()];
$allPromise = \Amp\all($promises);
$allPromise->when('\Amp\stop');
$result = (yield \Amp\first($promises));
});
$this->assertSame(3, $resolutionCount);
$this->assertSame(1, $result);
}
public function testNonPromiseValueImmediatelyResolvesFirstCombinator() {
$result = 0;
\Amp\run(function () use (&$result) {
$p1 = 42;
$p2 = (new Deferred)->promise();
$result = (yield \Amp\first([$p1, $p2]));
});
$this->assertSame(42, $result);
}
/**
* @expectedException \Amp\CombinatorException
* @expectedExceptionMessage All promises failed
*/
public function testFirstFailsIfAllPromisesFail() {
\Amp\run(function () use (&$result) {
$e1 = new \Exception("foo");
$e2 = new \Exception("bar");
$promises = [new Failure($e1), new Failure($e2)];
yield \Amp\first($promises);
});
}
/**
* @expectedException \Amp\TimeoutException
* @expectedExceptionMessage Promise resolution timed out
*/
public function testTimeout() {
\Amp\run(function () {
$pause = new \Amp\Pause(3000);
yield \Amp\timeout($pause, 10);
});
}
public function testTimeoutOnSuccess() {
$invoked = false;
\Amp\run(function () use (&$invoked) {
$promisor = new Deferred;
\Amp\once(function () use ($promisor) {
$promisor->succeed(42);
}, 10);
$result = (yield \Amp\timeout($promisor->promise(), 10000));
$this->assertSame(42, $result);
$invoked = true;
});
$this->assertTrue($invoked);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage nothing that is worth knowing can be taught
*/
public function testTimeoutOnFailure() {
\Amp\run(function () {
$promisor = new Deferred;
\Amp\once(function () use ($promisor) {
$promisor->fail(new \RuntimeException(
"nothing that is worth knowing can be taught"
));
}, 10);
$result = (yield \Amp\timeout($promisor->promise(), 10000));
});
}
public function testTimeoutIgnoresResultIfAlreadyComplete() {
$invoked = false;
\Amp\run(function () use (&$invoked) {
$promisor = new Deferred;
\Amp\once(function () use ($promisor) {
$promisor->succeed(42);
}, 100);
try {
$result = (yield \Amp\timeout($promisor->promise(), 10));
} catch (\RuntimeException $e) {
// ignore this
}
yield $promisor->promise();
$invoked = true;
});
$this->assertTrue($invoked);
}
public function testAllCombinatorResolution() {
$invoked = 0;
\Amp\run(function () use (&$invoked) {
list($a, $b) = (yield \Amp\all([
new Success(21),
new Success(2),
]));
$result = ($a * $b);
$this->assertSame(42, $result);
$invoked++;
});
$this->assertSame(1, $invoked);
}
public function testAllCombinatorResolutionWithNonPromises() {
$invoked = 0;
\Amp\run(function () use (&$invoked) {
list($a, $b, $c) = (yield \Amp\all([new Success(21), new Success(2), 10]));
$result = ($a * $b * $c);
$this->assertSame(420, $result);
$invoked++;
});
$this->assertSame(1, $invoked);
}
/**
* @expectedException \Exception
* @expectedExceptionMessage When in the chronicle of wasted time
*/
public function testAllCombinatorResolutionThrowsIfAnyOnePromiseFails() {
\Amp\run(function () {
list($a, $b) = (yield \Amp\all([
new Success(21),
new Failure(new \Exception('When in the chronicle of wasted time')),
]));
});
}
public function testExplicitAllCombinatorResolution() {
$invoked = 0;
\Amp\run(function () use (&$invoked) {
list($a, $b, $c) = (yield \Amp\all([
new Success(21),
new Success(2),
10
]));
$this->assertSame(420, ($a * $b * $c));
$invoked++;
});
$this->assertSame(1, $invoked);
}
public function testExplicitAnyCombinatorResolution() {
$invoked = 0;
\Amp\run(function () use (&$invoked) {
list($errors, $results) = (yield \Amp\any([
'a' => new Success(21),
'b' => new Failure(new \Exception('test')),
]));
$this->assertSame('test', $errors['b']->getMessage());
$this->assertSame(21, $results['a']);
$invoked++;
});
$this->assertSame(1, $invoked);
}
/**
* @expectedException \Amp\CombinatorException
*/
public function testExplicitSomeCombinatorResolutionFailsOnError() {
\Amp\run(function () {
yield \Amp\some([
'r1' => new Failure(new \RuntimeException),
'r2' => new Failure(new \RuntimeException),
]);
});
}
public function testPromisesNormalization() {
$completed = false;
\Amp\run(function () use (&$completed) {
$promisor = new Deferred;
$promisor->succeed(41);
$values = [
$promisor,
42,
new Success(43),
];
list($a, $b, $c) = (yield \Amp\all(\Amp\promises($values)));
$this->assertSame(41, $a);
$this->assertSame(42, $b);
$this->assertSame(43, $c);
$completed = true;
});
$this->assertTrue($completed);
}
public function testCoroutine() {
$invoked = 0;
\Amp\run(function () use (&$invoked) {
$co = function () use (&$invoked) {
yield new Success;
yield;
yield new Pause(25);
$invoked++;
};
$wrapped = \Amp\coroutine($co);
$wrapped();
});
$this->assertSame(1, $invoked);
}
public function testCoroutineWrapsNonGeneratorReturnInPromise() {
$co = \Amp\coroutine(function () {
return 42;
});
$out = $co();
$this->assertInstanceOf("\Amp\Success", $out);
$invoked = false;
$out->when(function ($error, $result) use (&$invoked) {
$this->assertNull($error);
$this->assertSame(42, $result);
$invoked = true;
});
$this->assertTrue($invoked);
}
public function testCoroutineReturnsPromiseResultUnmodified() {
$success = new \Amp\Success;
$co = \Amp\coroutine(function () use ($success) {
return $success;
});
$out = $co();
$this->assertSame($success, $out);
}
public function testNestedCoroutineResolutionContinuation() {
$invoked = 0;
\Amp\run(function () use (&$invoked) {
$co = function () use (&$invoked) {
yield new Success;
yield new Success;
yield new Success;
yield new Success;
yield new Success;
yield new CoroutineResult(42);
$invoked++;
};
$result = (yield \Amp\resolve($co()));
$this->assertSame(42, $result);
});
$this->assertSame(1, $invoked);
}
public function testCoroutineFauxReturnValue() {
$invoked = 0;
\Amp\run(function () use (&$invoked) {
$co = function () use (&$invoked) {
yield;
yield new CoroutineResult(42);
yield;
$invoked++;
};
$result = (yield \Amp\resolve($co()));
$this->assertSame(42, $result);
});
$this->assertSame(1, $invoked);
}
public function testResolveAcceptsGeneratorCallable() {
\Amp\run(function() {
$result = (yield \Amp\resolve(function () {
yield new CoroutineResult(42);
}));
$this->assertSame(42, $result);
});
}
/**
* @expectedException \LogicException
*/
public function testResolveNonGeneratorCallableThrows() {
\Amp\run(function() {
yield \Amp\resolve(function () {
return 42;
});
});
}
/**
* @expectedException \InvalidArgumentException
*/
public function testResolveInvalidArgumentThrows() {
\Amp\run(function() {
yield \Amp\resolve(42);
});
}
public function testResolutionFailuresAreThrownIntoGeneratorCoroutine() {
$invoked = 0;
\Amp\run(function () use (&$invoked) {
$foo = function () {
$a = (yield new Success(21));
$b = 1;
try {
yield new Failure(new \Exception("test"));
$this->fail("Code path should not be reached");
} catch (\Exception $e) {
$this->assertSame("test", $e->getMessage());
$b = 2;
}
};
$result = (yield \Amp\resolve($foo()));
$invoked++;
});
$this->assertSame(1, $invoked);
}
/**
* @expectedException \Exception
* @expectedExceptionMessage a moveable feast
*/
public function testExceptionOnInitialAdvanceFailsCoroutineResolution() {
\Amp\run(function () use (&$invoked) {
$co = function () {
throw new \Exception("a moveable feast");
yield;
};
$result = (yield \Amp\resolve($co()));
});
}
/**
* @dataProvider provideInvalidYields
*/
public function testInvalidYieldFailsCoroutineResolution($badYield) {
try {
\Amp\run(function () use (&$invoked, $badYield) {
$gen = function () use ($badYield) {
yield;
yield $badYield;
yield;
};
yield \Amp\resolve($gen());
});
$this->fail("execution should not reach this point");
} catch (\DomainException $e) {
$pos = strpos($e->getMessage(), "Unexpected yield (Promise|CoroutineResult|null expected);");
$this->assertSame(0, $pos);
return;
}
$this->fail("execution should not reach this point");
}
public function provideInvalidYields() {
return [
[42],
[3.14],
["string"],
[true],
[new \StdClass],
];
}
/**
* @expectedException \Exception
* @expectedExceptionMessage When in the chronicle of wasted time
*/
public function testUncaughtGeneratorExceptionFailsCoroutineResolution() {
$invoked = 0;
\Amp\run(function () use (&$invoked) {
$gen = function () {
yield;
throw new \Exception("When in the chronicle of wasted time");
yield;
};
yield \Amp\resolve($gen());
$invoked++;
});
$this->assertSame(1, $invoked);
}
public function testWait() {
$promisor = new Deferred;
\Amp\once(function () use ($promisor) {
$promisor->succeed(42);
}, 10);
$result = \Amp\wait($promisor->promise());
$this->assertSame(42, $result);
}
/**
* @expectedException \Exception
* @expectedExceptionMessage If the reader prefers, this code may be regarded as fiction
*/
public function testWaitError() {
$promisor = new Deferred;
\Amp\once(function () use ($promisor) {
$promisor->fail(new \Exception(
"If the reader prefers, this code may be regarded as fiction"
));
}, 10);
\Amp\wait($promisor->promise());
}
}

View File

@ -1,22 +0,0 @@
<?php
namespace Amp\Test;
use Amp\LibeventReactor;
class LibeventReactorTest extends ReactorTest {
protected function setUp() {
if (extension_loaded("libevent")) {
\Amp\reactor($assign = new LibeventReactor);
} else {
$this->markTestSkipped(
"libevent extension not loaded"
);
}
}
public function testGetLoop() {
$result = \Amp\reactor()->getLoop();
$this->assertInternalType("resource", $result);
}
}

View File

@ -1,31 +0,0 @@
<?php
namespace Amp\Test;
use Amp\NativeReactor;
class NativeReactorTest extends ReactorTest {
protected function setUp() {
\Amp\reactor($assign = new NativeReactor);
}
public function testOnSignalWatcher() {
if (!\extension_loaded("pcntl")) {
$this->markTestSkipped(
"ext/pcntl required to test onSignal() capture"
);
} else {
parent::testOnSignalWatcher();
}
}
public function testInitiallyDisabledOnSignalWatcher() {
if (!\extension_loaded("pcntl")) {
$this->markTestSkipped(
"ext/pcntl required to test onSignal() capture"
);
} else {
parent::testInitiallyDisabledOnSignalWatcher();
}
}
}

View File

@ -2,39 +2,42 @@
namespace Amp\Test;
use Amp;
use Amp\Pause;
use Amp\NativeReactor;
use Interop\Async\Loop;
class PauseTest extends \PHPUnit_Framework_TestCase {
protected function setUp() {
\Amp\reactor($assign = new NativeReactor);
}
/**
* @dataProvider provideBadMillisecondArgs
* @expectedException \DomainException
* @expectedExceptionMessage Pause timeout must be greater than or equal to 1 millisecond
* @expectedException \InvalidArgumentException
*/
public function testCtorThrowsOnBadMillisecondParam($arg) {
\Amp\run(function () use ($arg) {
new Pause($arg);
});
$pause = new Pause($arg);
}
public function provideBadMillisecondArgs() {
return [
[0],
[-3.14],
[-1],
];
}
public function testPauseYield() {
$endReached = false;
\Amp\run(function () use (&$endReached) {
$result = (yield new Pause(1));
$this->assertNull($result);
$endReached = true;
public function testPause() {
$time = 100;
$value = "test";
$start = microtime(true);
Loop::execute(function () use (&$result, $time, $value) {
$awaitable = new Pause($time, $value);
$callback = function ($exception, $value) use (&$result) {
$result = $value;
};
$awaitable->when($callback);
});
$this->assertTrue($endReached);
$this->assertLessThanOrEqual($time, microtime(true) - $start);
$this->assertSame($value, $result);
}
}

View File

@ -1,9 +0,0 @@
<?php
namespace Amp\Test;
class PlaceholderPrivateTest extends PlaceholderTest {
protected function getPromisor() {
return new PromisorPrivateImpl;
}
}

View File

@ -1,9 +0,0 @@
<?php
namespace Amp\Test;
class PlaceholderPublicTest extends PlaceholderTest {
protected function getPromisor() {
return new PromisorPublicImpl;
}
}

View File

@ -1,123 +0,0 @@
<?php
namespace Amp\Test;
use Amp\NativeReactor;
abstract class PlaceholderTest {
abstract protected function getPromisor();
public function testWhenCallbackDataPassed() {
$invoked = 0;
$promisor = $this->getPromisor();
$promise = $promisor->promise();
$promisor->succeed(42);
$promise->when(function($e, $r, $d) use (&$invoked) {
$this->assertNull($e);
$this->assertSame(42, $r);
$this->assertSame("zanzibar", $d);
++$invoked;
}, "zanzibar");
$this->assertSame(1, $invoked);
}
public function testWatchCallbackDataPassed() {
$invoked = 0;
$promisor = $this->getPromisor();
$promise = $promisor->promise();
$promise->watch(function($p, $d) use (&$invoked) {
$this->assertSame(42, $p);
$this->assertSame("zanzibar", $d);
$invoked++;
}, "zanzibar");
$promisor->update(42);
$promisor->update(42);
$this->assertSame(2, $invoked);
}
public function testWatchCallbackNotInvokedIfAlreadySucceeded() {
$invoked = 0;
$promisor = $this->getPromisor();
$promise = $promisor->promise();
$promisor->succeed(42);
$promise->watch(function($p, $d) use (&$invoked) {
$invoked++;
});
$this->assertSame(0, $invoked);
}
public function testWatchCallbackNotInvokedIfAlreadyFailed() {
$invoked = 0;
$promisor = $this->getPromisor();
$promise = $promisor->promise();
$exception = new \Exception('test');
$promisor->fail($exception);
$promise->watch(function($p, $d) use (&$invoked) {
$invoked++;
});
$this->assertSame(0, $invoked);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Promise already resolved
*/
public function testSucceedThrowsIfAlreadyResolved() {
$promisor = $this->getPromisor();
$promisor->succeed(42);
$promisor->succeed('zanzibar');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage A Promise cannot act as its own resolution result
*/
public function testSucceedThrowsIfPromiseIsTheResolutionValue() {
$promisor = $this->getPromisor();
$promise = $promisor->promise();
$promisor->succeed($promise);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Promise already resolved
*/
public function testFailThrowsIfAlreadyResolved() {
$promisor = $this->getPromisor();
$promisor->succeed(42);
$promisor->fail(new \Exception);
}
public function testSucceedingWithPromisePipelinesResult() {
(new NativeReactor)->run(function($reactor) {
$promisor = $this->getPromisor();
$next = $this->getPromisor();
$reactor->once(function() use ($next) {
$next->succeed(42);
}, $msDelay = 1);
$promisor->succeed($next->promise());
$this->assertSame(42, (yield $promisor->promise()));
});
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage fugazi
*/
public function testFailingWithPromisePipelinesResult() {
(new NativeReactor)->run(function($reactor) {
$promisor = $this->getPromisor();
$next = $this->getPromisor();
$reactor->once(function() use ($next) {
$next->fail(new \RuntimeException('fugazi'));
}, $msDelay = 10);
$promisor->succeed($next->promise());
yield $promisor->promise();
});
}
}

View File

@ -1,135 +0,0 @@
<?php
namespace Amp\Test;
class PromiseStreamTest extends BaseTest {
public function testStream() {
$endReached = false;
\Amp\run(function () use (&$endReached) {
$promisor = new \Amp\Deferred;
$stream = new \Amp\PromiseStream($promisor->promise());
$i = 0;
\Amp\repeat(function ($watcherId) use ($promisor, &$i) {
$i++;
$promisor->update("test{$i}");
if ($i === 3) {
$promisor->succeed();
\Amp\cancel($watcherId);
}
}, 10);
$results = [];
while (yield $stream->valid()) {
$results[] = $stream->consume();
}
$this->assertSame(["test1", "test2", "test3"], $results);
$endReached = true;
});
$this->assertTrue($endReached);
}
public function testStreamReturnsPromiseResolutionForFirstConsumeCallAfterSuccess() {
$endReached = false;
\Amp\run(function () use (&$endReached) {
$promisor = new \Amp\Deferred;
$stream = new \Amp\PromiseStream($promisor->promise());
$i = 0;
\Amp\repeat(function ($watcherId) use ($promisor, &$i) {
$i++;
$promisor->update("test{$i}");
if ($i === 3) {
$promisor->succeed(42);
\Amp\cancel($watcherId);
}
}, 10);
$results = [];
while (yield $stream->valid()) {
$stream->consume();
}
$this->assertSame(42, $stream->consume());
$endReached = true;
});
$this->assertTrue($endReached);
}
public function testStreamRetainsUpdatesUntilInitialized() {
$endReached = false;
\Amp\run(function () use (&$endReached) {
$promisor = new \Amp\Deferred;
$stream = new \Amp\PromiseStream($promisor->promise());
$promisor->update("foo");
$promisor->update("bar");
$promisor->update("baz");
$promisor->succeed();
$results = [];
while (yield $stream->valid()) {
$results[] = $stream->consume();
}
$endReached = true;
$this->assertSame(["foo", "bar", "baz"], $results);
});
$this->assertTrue($endReached);
}
/**
* @expectedException \Exception
* @expectedExceptionMessage test
*/
public function testStreamThrowsIfPromiseFails() {
\Amp\run(function () {
$i = 0;
$promisor = new \Amp\Deferred;
\Amp\repeat(function ($watcherId) use (&$i, $promisor) {
$i++;
$promisor->update($i);
if ($i === 2) {
\Amp\cancel($watcherId);
$promisor->fail(new \Exception(
"test"
));
}
}, 10);
$stream = new \Amp\PromiseStream($promisor->promise());
$results = [];
while (yield $stream->valid()) {
$results[] = $stream->consume();
}
});
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot advance PromiseStream beyond unresolved index 0
*/
public function testPrematureConsumptionThrows() {
\Amp\run(function () {
$promisor = new \Amp\Deferred;
$stream = new \Amp\PromiseStream($promisor->promise());
$results = [];
$stream->consume();
});
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot advance PromiseStream beyond completed index 1
*/
public function testConsumeAfterStreamCompletionThrows() {
\Amp\run(function () {
$promisor = new \Amp\Deferred;
$promisor->update(0);
$promisor->succeed(1);
$stream = new \Amp\PromiseStream($promisor->promise());
$results = [];
$stream->consume();
$stream->consume();
$stream->consume();
});
}
}

View File

@ -1,12 +0,0 @@
<?php
namespace Amp\Test;
use Amp\Promisor;
use Amp\Test\PromisorPrivateImpl;
class PromisorPrivateTest extends PromisorTest {
protected function getPromisor() {
return new PromisorPrivateImpl;
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace Amp\Test;
use Amp\Promisor;
use Amp\Test\PromisorPublicImpl;
class PromisorPublicTest extends PromisorTest {
protected function getPromisor() {
return new PromisorPublicImpl;
}
public function testPromiseReturnsSelf() {
$promisor = new PromisorPublicImpl;
$this->assertSame($promisor, $promisor->promise());
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Throwable Exception instance required to fail a promise
* @dataProvider provideBadFailureArguments
*/
public function testResolvingErrorWithNonExceptionThrows($badArg) {
$promisor = $this->getPromisor();
$promisor->fail($badArg);
}
public function provideBadFailureArguments() {
return [
[1],
[true],
[new \StdClass],
];
}
}

View File

@ -1,157 +0,0 @@
<?php
namespace Amp\Test;
use Amp\NativeReactor;
abstract class PromisorTest extends \PHPUnit_Framework_TestCase {
abstract protected function getPromisor();
protected function setUp() {
\Amp\reactor($assign = new NativeReactor);
}
public function testWhenInvokesCallbackWithResultIfAlreadySucceeded() {
$invoked = 0;
$promisor = $this->getPromisor();
$promise = $promisor->promise();
$promisor->succeed(42);
$promise->when(function ($e, $r) use (&$invoked) {
$this->assertSame(42, $r);
$this->assertNull($e);
++$invoked;
});
$this->assertSame(1, $invoked);
}
public function testWhenInvokesCallbackWithErrorIfAlreadyFailed() {
$invoked = 0;
$promisor = $this->getPromisor();
$promise = $promisor->promise();
$exception = new \Exception('test');
$promisor->fail($exception);
$promise->when(function ($e, $r) use ($exception, &$invoked) {
$invoked++;
$this->assertSame($exception, $e);
$this->assertNull($r);
});
$this->assertSame(1, $invoked);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Promise already resolved
*/
public function testSucceedThrowsIfAlreadyResolved() {
$promisor = $this->getPromisor();
$promisor->succeed(42);
$promisor->succeed('zanzibar');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage A Promise cannot act as its own resolution result
*/
public function testSucceedThrowsIfPromiseIsTheResolutionValue() {
$promisor = $this->getPromisor();
$promise = $promisor->promise();
$promisor->succeed($promise);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Promise already resolved
*/
public function testFailThrowsIfAlreadyResolved() {
$promisor = $this->getPromisor();
$promisor->succeed(42);
$promisor->fail(new \Exception);
}
public function testSucceedingWithPromisePipelinesResult() {
\Amp\run(function () {
$next = $this->getPromisor();
$promisor = $this->getPromisor();
$promisor->succeed($next->promise());
\Amp\once(function () use ($next) {
$next->succeed(42);
}, $msDelay = 10);
yield;
$result = (yield $promisor->promise());
$this->assertSame(42, $result);
});
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage fugazi
*/
public function testFailingWithPromisePipelinesResult() {
\Amp\run(function () {
$promisor = $this->getPromisor();
$next = $this->getPromisor();
\Amp\once(function () use ($next) {
$next->fail(new \RuntimeException('fugazi'));
}, $msDelay = 10);
yield;
$promisor->succeed($next->promise());
yield $promisor->promise();
});
}
public function testUpdate() {
$updatable = 0;
\Amp\run(function () use (&$updatable) {
$i = 0;
$promisor = $this->getPromisor();
$updater = function ($watcherId) use ($promisor, &$i) {
$promisor->update(++$i);
if ($i === 3) {
\Amp\cancel($watcherId);
// reactor run loop should now be able to exit
}
};
$promise = $promisor->promise();
$promise->watch(function ($updateData) use (&$updatable) {
$updatable += $updateData;
});
\Amp\repeat($updater, $msDelay = 10);
});
$this->assertSame(6, $updatable);
}
public function testUpdateArgs() {
$updates = new \StdClass;
$updates->arr = [];
$promisor = $this->getPromisor();
$promise = $promisor->promise();
$promise->watch(function ($progress, $cbData) use ($updates) {
$updates->arr[] = \func_get_args();
}, "cb_data");
$promisor->update(1);
$promisor->update(2);
$promisor->update(3);
$expected = [
[1, "cb_data"],
[2, "cb_data"],
[3, "cb_data"],
];
$this->assertSame($expected, $updates->arr);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot update resolved promise
*/
public function testUpdateThrowsIfPromiseAlreadyResolved() {
$promisor = $this->getPromisor();
$promisor->succeed();
$promisor->update(42);
}
}

View File

@ -1,716 +0,0 @@
<?php
namespace Amp\Test;
use Amp\UvReactor;
abstract class ReactorTest extends BaseTest {
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot stop(); event reactor not currently active
*/
public function testStopThrowsIfNotCurrentlyRunning() {
\Amp\stop();
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot run() recursively; event reactor already active
*/
public function testRecursiveRunCallThrows() {
\Amp\run(function () {
\Amp\run();
});
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot tick() recursively; event reactor already active
*/
public function testRecursiveTickCallThrows() {
\Amp\immediately('\Amp\tick');
\Amp\tick();
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot tick() recursively; event reactor already active
*/
public function testRecursiveTickCallThrowsInsideRun() {
\Amp\run(function () {
\Amp\tick();
});
}
public function testImmediatelyWatcherKeepAliveRunResult() {
$invoked = false;
\Amp\run(function () use (&$invoked) {
\Amp\immediately(function () use (&$invoked) {
$invoked = true;
}, ["keep_alive" => false]);
});
$this->assertFalse($invoked);
}
public function testOnceWatcherKeepAliveRunResult() {
$invoked = false;
\Amp\run(function () use (&$invoked) {
\Amp\once(function () use (&$invoked) {
$invoked = true;
}, 2000, $options = ["keep_alive" => false]);
});
$this->assertFalse($invoked);
}
public function testRepeatWatcherKeepAliveRunResult() {
$invoked = false;
\Amp\run(function () use (&$invoked) {
\Amp\repeat(function () use (&$invoked) {
$invoked = true;
}, 2000, $options = ["keep_alive" => false]);
});
$this->assertFalse($invoked);
}
public function testOnReadableWatcherKeepAliveRunResult() {
\Amp\run(function () {
\Amp\onReadable(STDIN, function () {
// empty
}, $options = ["keep_alive" => false]);
});
}
public function testOnWritableWatcherKeepAliveRunResult() {
\Amp\run(function () {
\Amp\onWritable(STDOUT, function () {
// empty
}, $options = ["keep_alive" => false]);
});
}
public function testOnSignalWatcherKeepAliveRunResult() {
if (!\extension_loaded("pcntl") && !\Amp\reactor() instanceof UvReactor) {
$this->markTestSkipped("ext/pcntl or UvReactor required to test onSignal() registration");
}
\Amp\run(function () {
\Amp\onSignal(SIGUSR1, function () {
// empty
}, $options = ["keep_alive" => false]);
});
}
/**
* @dataProvider provideRegistrationArgs
*/
public function testWatcherKeepAliveRegistrationInfo($type, $args) {
if ($type === "onSignal") {
if (!\extension_loaded("pcntl") && !\Amp\reactor() instanceof UvReactor) {
$this->markTestSkipped("ext/pcntl or UvReactor required to test onSignal() registration");
}
$requiresCancel = true;
} else {
$requiresCancel = false;
}
$func = '\Amp\\' . $type;
if (substr($type, 0, 2) === "on" && $type !== "once") {
$type = "on_" . lcfirst(substr($type, 2));
}
// keep_alive is the default
$watcherId1 = \call_user_func_array($func, $args);
$info = \Amp\info();
$expected = ["enabled" => 1, "disabled" => 0];
$this->assertSame($expected, $info[$type]);
$this->assertSame(1, $info["keep_alive"]);
// explicitly keep_alive even though it's the default setting
$argsCopy = $args;
$argsCopy[] = ["keep_alive" => true];
$watcherId2 = \call_user_func_array($func, $argsCopy);
$info = \Amp\info();
$expected = ["enabled" => 2, "disabled" => 0];
$this->assertSame($expected, $info[$type]);
$this->assertSame(2, $info["keep_alive"]);
// disabling a keep_alive watcher should decrement the count
\Amp\disable($watcherId2);
$info = \Amp\info();
$this->assertSame(1, $info["keep_alive"]);
// enabling a keep_alive watcher should increment the count
\Amp\enable($watcherId2);
$info = \Amp\info();
$this->assertSame(2, $info["keep_alive"]);
// cancelling a keep_alive watcher should decrement the count
\Amp\cancel($watcherId2);
$info = \Amp\info();
$this->assertSame(1, $info["keep_alive"]);
// keep_alive => false should leave the count untouched
$argsCopy = $args;
$argsCopy[] = ["keep_alive" => false];
$watcherId2 = \call_user_func_array($func, $argsCopy);
$info = \Amp\info();
$expected = ["enabled" => 2, "disabled" => 0];
$this->assertSame($expected, $info[$type]);
$this->assertSame(1, $info["keep_alive"]);
if ($requiresCancel) {
\Amp\cancel($watcherId1);
\Amp\cancel($watcherId2);
}
}
public function provideRegistrationArgs() {
$args = [
["immediately", [function () {}]],
["once", [function () {}, 5000]],
["repeat", [function () {}, 5000]],
["onWritable", [\STDOUT, function () {}]],
["onReadable", [\STDIN, function () {}]],
];
$args[] = ["onSignal", [defined('SIGUSR1') ? \SIGUSR1 : -1, function () {}]];
return $args;
}
/**
* @dataProvider provideRegistrationArgs
*/
public function testWatcherRegistrationAndCancellationInfo($type, $args) {
if ($type === "onSignal") {
if (!\extension_loaded("pcntl") && !\Amp\reactor() instanceof UvReactor) {
$this->markTestSkipped("ext/pcntl or UvReactor required to test onSignal() registration");
}
}
$func = '\Amp\\' . $type;
if (substr($type, 0, 2) === "on" && $type !== "once") {
$type = "on_" . lcfirst(substr($type, 2));
}
$watcherId = \call_user_func_array($func, $args);
$this->assertInternalType("string", $watcherId);
$info = \Amp\info();
$expected = ["enabled" => 1, "disabled" => 0];
$this->assertSame($expected, $info[$type]);
// invoke enable() on active watcher to ensure it has no side-effects
\Amp\enable($watcherId);
$info = \Amp\info();
$expected = ["enabled" => 1, "disabled" => 0];
$this->assertSame($expected, $info[$type]);
// invoke disable() twice to ensure it has no side-effects
\Amp\disable($watcherId);
\Amp\disable($watcherId);
$info = \Amp\info();
$expected = ["enabled" => 0, "disabled" => 1];
$this->assertSame($expected, $info[$type]);
\Amp\cancel($watcherId);
$info = \Amp\info();
$expected = ["enabled" => 0, "disabled" => 0];
$this->assertSame($expected, $info[$type]);
$watcherId = \call_user_func_array($func, $args);
$info = \Amp\info();
$expected = ["enabled" => 1, "disabled" => 0];
$this->assertSame($expected, $info[$type]);
\Amp\disable($watcherId);
$info = \Amp\info();
$expected = ["enabled" => 0, "disabled" => 1];
$this->assertSame($expected, $info[$type]);
\Amp\enable($watcherId);
$info = \Amp\info();
$expected = ["enabled" => 1, "disabled" => 0];
$this->assertSame($expected, $info[$type]);
\Amp\cancel($watcherId);
$info = \Amp\info();
$expected = ["enabled" => 0, "disabled" => 0];
$this->assertSame($expected, $info[$type]);
// invoke cancel() again to ensure it has no side-effects
\Amp\cancel($watcherId);
}
public function testEnableHasNoEffectOnNonexistentWatcher() {
\Amp\enable("nonexistentWatcher");
}
public function testDisableHasNoEffectOnNonexistentWatcher() {
\Amp\disable("nonexistentWatcher");
}
public function testCancelHasNoEffectOnNonexistentWatcher() {
\Amp\cancel("nonexistentWatcher");
}
/**
* @expectedException \Exception
* @expectedExceptionMessage coroutine error
*/
public function testImmediateCoroutineResolutionError() {
\Amp\run(function () {
yield;
yield new \Amp\Pause(10);
throw new \Exception("coroutine error");
});
}
public function testOnErrorCapturesUncaughtException() {
$msg = "";
\Amp\onError(function ($error) use (&$msg) {
$msg = $error->getMessage();
});
\Amp\run(function () {
throw new \Exception("coroutine error");
});
$this->assertSame("coroutine error", $msg);
}
/**
* @expectedException \Exception
* @expectedExceptionMessage errorception
*/
public function testOnErrorFailure() {
\Amp\onError(function () {
throw new \Exception("errorception");
});
\Amp\run(function () {
yield;
yield new \Amp\Pause(10);
throw new \Exception("coroutine error");
});
}
public function testEnablingWatcherAllowsSubsequentInvocation() {
$increment = 0;
$watcherId = \Amp\immediately(function () use (&$increment) {
$increment++;
});
\Amp\disable($watcherId);
\Amp\once('\Amp\stop', $msDelay = 50);
\Amp\run();
$this->assertEquals(0, $increment);
\Amp\enable($watcherId);
\Amp\once('\Amp\stop', $msDelay = 50);
\Amp\run();
$this->assertEquals(1, $increment);
}
public function testUnresolvedEventsAreReenabledOnRunFollowingPreviousStop() {
$increment = 0;
\Amp\once(function () use (&$increment) {
$increment++;
\Amp\stop();
}, $msDelay = 150);
\Amp\run('\Amp\stop');
$this->assertEquals(0, $increment);
\usleep(150000);
\Amp\run();
$this->assertEquals(1, $increment);
}
public function testTimerWatcherParameterOrder() {
$counter = 0;
\Amp\immediately(function ($watcherId) use (&$counter) {
$this->assertInternalType("string", $watcherId);
if (++$counter === 3) {
\Amp\stop();
}
});
\Amp\once(function ($watcherId) use (&$counter) {
$this->assertInternalType("string", $watcherId);
if (++$counter === 3) {
\Amp\stop();
}
}, $msDelay = 1);
\Amp\repeat(function ($watcherId) use (&$counter) {
$this->assertInternalType("string", $watcherId);
\Amp\cancel($watcherId);
if (++$counter === 3) {
\Amp\stop();
}
}, $msDelay = 1);
\Amp\run();
}
public function testStreamWatcherParameterOrder() {
$invoked = 0;
\Amp\onWritable(STDOUT, function ($watcherId, $stream) use (&$invoked) {
$this->assertInternalType("string", $watcherId);
$this->assertSame(STDOUT, $stream);
$invoked++;
\Amp\cancel($watcherId);
});
\Amp\run();
$this->assertSame(1, $invoked);
}
public function testDisablingWatcherPreventsSubsequentInvocation() {
$increment = 0;
$watcherId = \Amp\immediately(function () use (&$increment) {
$increment++;
});
\Amp\disable($watcherId);
\Amp\once('\Amp\stop', $msDelay = 50);
\Amp\run();
$this->assertEquals(0, $increment);
}
public function testImmediateExecution() {
$increment = 0;
\Amp\immediately(function () use (&$increment) {
$increment++;
});
\Amp\tick();
$this->assertEquals(1, $increment);
}
public function testImmediatelyCallbacksDontRecurseInSameTick() {
$increment = 0;
\Amp\immediately(function () use (&$increment) {
$increment++;
\Amp\immediately(function () use (&$increment) {
$increment++;
});
});
\Amp\tick();
$this->assertEquals(1, $increment);
}
public function testTickExecutesReadyEvents() {
$increment = 0;
\Amp\immediately(function () use (&$increment) {
$increment++;
});
\Amp\tick();
$this->assertEquals(1, $increment);
}
public function testRunExecutesEventsUntilExplicitlyStopped() {
$increment = 0;
\Amp\repeat(function ($watcherId) use (&$increment) {
$increment++;
if ($increment === 10) {
\Amp\cancel($watcherId);
}
}, $msInterval = 5);
\Amp\run();
$this->assertEquals(10, $increment);
}
/**
* @expectedException RuntimeException
* @expectedExceptionMessage test
*/
public function testReactorAllowsExceptionToBubbleUpDuringTick() {
\Amp\immediately(function () {
throw new \RuntimeException("test");
});
\Amp\tick();
}
/**
* @expectedException RuntimeException
* @expectedExceptionMessage test
*/
public function testReactorAllowsExceptionToBubbleUpDuringRun() {
\Amp\immediately(function () {
throw new \RuntimeException("test");
});
\Amp\run();
}
/**
* @expectedException RuntimeException
* @expectedExceptionMessage test
*/
public function testReactorAllowsExceptionToBubbleUpFromRepeatingAlarmDuringRun() {
\Amp\repeat(function () {
throw new \RuntimeException("test");
}, $msInterval = 0);
\Amp\run();
}
public function testOnSignalWatcher() {
if (!\extension_loaded("posix") || !(\extension_loaded("pcntl") || \Amp\reactor() instanceof UvReactor)) {
$this->markTestSkipped(
"ext/posix and UvReactor or ext/pcntl required to test onSignal() capture"
);
}
$this->expectOutputString("caught SIGUSR1");
\Amp\run(function () {
\Amp\once(function () {
\posix_kill(\getmypid(), \SIGUSR1);
\Amp\once(function () {
\Amp\stop();
}, 100);
}, 1);
\Amp\onSignal(SIGUSR1, function ($watcherId) {
\Amp\cancel($watcherId);
echo "caught SIGUSR1";
});
});
}
public function testInitiallyDisabledOnSignalWatcher() {
if (!\extension_loaded("posix") || !(\extension_loaded("pcntl") || \Amp\reactor() instanceof UvReactor)) {
$this->markTestSkipped(
"ext/posix and UvReactor or ext/pcntl required to test onSignal() capture"
);
}
$this->expectOutputString("caught SIGUSR1");
\Amp\run(function () {
$sigWatcherId = \Amp\onSignal(SIGUSR1, function () {
echo "caught SIGUSR1";
\Amp\stop();
}, $options = ["enable" => false]);
\Amp\once(function () use ($sigWatcherId) {
\Amp\enable($sigWatcherId);
\Amp\once(function () use ($sigWatcherId) {
\posix_kill(\getmypid(), \SIGUSR1);
}, 10);
}, 10);
});
}
public function testCancelRemovesWatcher() {
$watcherId = \Amp\once(function (){
$this->fail('Watcher was not cancelled as expected');
}, $msDelay = 20);
\Amp\immediately(function () use ($watcherId) {
\Amp\cancel($watcherId);
});
\Amp\once('\Amp\stop', $msDelay = 5);
\Amp\run();
}
public function testOnWritableWatcher() {
$flag = false;
\Amp\onWritable(STDOUT, function () use (&$flag) {
$flag = true;
\Amp\stop();
});
\Amp\once('\Amp\stop', $msDelay = 50);
\Amp\run();
$this->assertTrue($flag);
}
public function testInitiallyDisabledWriteWatcher() {
$increment = 0;
$options = ["enable" => false];
\Amp\onWritable(STDOUT, function () use (&$increment) {
$increment++;
}, $options);
\Amp\once('\Amp\stop', $msDelay = 50);
\Amp\run();
$this->assertSame(0, $increment);
}
public function testInitiallyDisabledWriteWatcherIsTriggeredOnceEnabled() {
$increment = 0;
$options = ["enable" => false];
$watcherId = \Amp\onWritable(STDOUT, function () use (&$increment) {
$increment++;
}, $options);
\Amp\immediately(function () use ($watcherId) {
\Amp\enable($watcherId);
});
\Amp\once('\Amp\stop', $msDelay = 250);
\Amp\run();
$this->assertTrue($increment > 0);
}
/**
* @expectedException RuntimeException
*/
public function testStreamWatcherDoesntSwallowExceptions() {
\Amp\onWritable(STDOUT, function () { throw new \RuntimeException; });
\Amp\once('\Amp\stop', $msDelay = 50);
\Amp\run();
}
public function testGarbageCollection() {
\Amp\once('\Amp\stop', $msDelay = 100);
\Amp\run();
}
public function testOnStartGeneratorResolvesAutomatically() {
$test = '';
\Amp\run(function () use (&$test) {
yield;
$test = "Thus Spake Zarathustra";
\Amp\once('\Amp\stop', 1);
});
$this->assertSame("Thus Spake Zarathustra", $test);
}
public function testImmediatelyGeneratorResolvesAutomatically() {
$test = '';
\Amp\immediately(function () use (&$test) {
yield;
$test = "The abyss will gaze back into you";
\Amp\once('\Amp\stop', 50);
});
\Amp\run();
$this->assertSame("The abyss will gaze back into you", $test);
}
public function testOnceGeneratorResolvesAutomatically() {
$test = '';
$gen = function () use (&$test) {
yield;
$test = "There are no facts, only interpretations.";
\Amp\once('\Amp\stop', 50);
};
\Amp\once($gen, 1);
\Amp\run();
$this->assertSame("There are no facts, only interpretations.", $test);
}
public function testRepeatGeneratorResolvesAutomatically() {
$test = '';
$gen = function ($watcherId) use (&$test) {
\Amp\cancel($watcherId);
yield;
$test = "Art is the supreme task";
\Amp\stop();
};
\Amp\repeat($gen, 50);
\Amp\run();
$this->assertSame("Art is the supreme task", $test);
}
public function testOnErrorCallbackInterceptsUncaughtException() {
$var = null;
\Amp\onError(function ($e) use (&$var) {
$var = $e->getMessage();
});
\Amp\run(function () { throw new \Exception('test'); });
$this->assertSame('test', $var);
}
public function testReactorRunsUntilNoWatchersRemain() {
$var1 = 0;
\Amp\repeat(function ($watcherId) use (&$var1) {
if (++$var1 === 3) {
\Amp\cancel($watcherId);
}
}, 0);
$var2 = 0;
\Amp\onWritable(STDOUT, function ($watcherId) use (&$var2) {
if (++$var2 === 4) {
\Amp\cancel($watcherId);
}
});
\Amp\run();
$this->assertSame(3, $var1);
$this->assertSame(4, $var2);
}
public function testReactorRunsUntilNoWatchersRemainWhenStartedImmediately() {
$var1 = 0;
$var2 = 0;
\Amp\run(function () use (&$var1, &$var2) {
\Amp\repeat(function ($watcherId) use (&$var1) {
if (++$var1 === 3) {
\Amp\cancel($watcherId);
}
}, 0);
\Amp\onWritable(STDOUT, function ($watcherId) use (&$var2) {
if (++$var2 === 4) {
\Amp\cancel($watcherId);
}
});
});
$this->assertSame(3, $var1);
$this->assertSame(4, $var2);
}
public function testOptionalCallbackDataPassedOnInvocation() {
$callbackData = new \StdClass;
$options = ["cb_data" => $callbackData];
\Amp\immediately(function ($watcherId, $callbackData) {
$callbackData->immediately = true;
}, $options);
\Amp\once(function ($watcherId, $callbackData) {
$callbackData->once = true;
}, 1, $options);
\Amp\repeat(function ($watcherId, $callbackData) {
$callbackData->repeat = true;
\Amp\cancel($watcherId);
}, 1, $options);
\Amp\onWritable(STDERR, function ($watcherId, $stream, $callbackData) {
$callbackData->onWritable = true;
\Amp\cancel($watcherId);
}, $options);
\Amp\run();
$this->assertTrue($callbackData->immediately);
$this->assertTrue($callbackData->once);
$this->assertTrue($callbackData->repeat);
$this->assertTrue($callbackData->onWritable);
}
public function testOptionalRepeatWatcherDelay() {
$invoked = false;
\Amp\repeat(function ($watcherId) use (&$invoked) {
$invoked = true;
\Amp\cancel($watcherId);
}, $msInterval = 10000, $options = ["ms_delay" => 1]);
\Amp\once('\Amp\stop', 50);
\Amp\run();
$this->assertTrue($invoked);
}
public function testOptionalDisable() {
$options = ["enable" => false];
\Amp\immediately(function ($watcherId, $callbackData) {
$this->fail("disabled watcher should not invoke callback");
}, $options);
\Amp\once(function ($watcherId, $callbackData) {
$this->fail("disabled watcher should not invoke callback");
}, 1, $options);
\Amp\repeat(function ($watcherId, $callbackData) {
$this->fail("disabled watcher should not invoke callback");
\Amp\cancel($watcherId);
}, 1, $options);
\Amp\onWritable(STDERR, function ($watcherId, $stream, $callbackData) {
$this->fail("disabled watcher should not invoke callback");
\Amp\cancel($watcherId);
}, $options);
\Amp\run();
}
}

View File

@ -2,6 +2,11 @@
namespace Amp\Test;
class StructTestFixture {
use \Amp\Struct;
public $callback;
}
class StructTest extends \PHPUnit_Framework_TestCase {
/**
* @expectedException \DomainException

View File

@ -1,55 +0,0 @@
<?php
namespace Amp\Test;
use Amp\UvReactor;
class UvReactorTest extends ReactorTest {
public static function setUpBeforeClass() {
if (!defined('SIGUSR1') && extension_loaded("uv")) {
define('SIGUSR1', \Uv::SIGUSR1);
}
}
protected function setUp() {
if (extension_loaded("uv")) {
\Amp\reactor($assign = new UvReactor);
} else {
$this->markTestSkipped(
"php-uv extension not loaded"
);
}
}
public function testGetLoop() {
$result = \Amp\reactor()->getLoop();
$this->assertInternalType("resource", $result);
}
public function testOnSignalWatcherKeepAliveRunResult() {
\Amp\run(function () {
\Amp\onSignal(\Uv::SIGUSR1, function () {
// empty
}, $options = ["keep_alive" => false]);
});
}
/**
* We need to override the default ReactorTest function to use the correct signal constant
*/
public function provideRegistrationArgs() {
$result = [
["immediately", [function () {}]],
["once", [function () {}, 5000]],
["repeat", [function () {}, 5000]],
["onWritable", [\STDOUT, function () {}]],
["onReadable", [\STDIN, function () {}]],
];
if (\extension_loaded("uv")) {
$result[] = ["onSignal", [\Uv::SIGUSR1, function () {}]];
}
return $result;
}
}

View File

@ -1,18 +0,0 @@
<?php
namespace Amp\Test;
require __DIR__ . "/../vendor/autoload.php";
error_reporting(E_ALL);
class PromisorPrivateImpl implements \Amp\Promisor {
use \Amp\PrivatePromisor;
}
class PromisorPublicImpl implements \Amp\Promisor, \Amp\Promise {
use \Amp\PublicPromisor;
}
class StructTestFixture {
use \Amp\Struct;
public $callback;
}