mirror of
https://github.com/danog/amp.git
synced 2024-11-26 20:15:00 +01:00
Initial tests plus some fixes
This commit is contained in:
parent
4ed8e65468
commit
3f654cbd5b
@ -18,7 +18,8 @@
|
||||
"async-interop/event-loop-implementation": "dev-master"
|
||||
},
|
||||
"require-dev": {
|
||||
"amphp/loop": "dev-master"
|
||||
"amphp/loop": "dev-master",
|
||||
"phpunit/phpunit": "^4|^5"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"autoload": {
|
||||
|
@ -4,6 +4,7 @@ namespace Amp;
|
||||
|
||||
use Interop\Async\Awaitable;
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
try {
|
||||
if (@assert(false)) {
|
||||
production: // PHP 7 production environment (zend.assertions=0)
|
||||
@ -75,4 +76,4 @@ try {
|
||||
}
|
||||
} catch (\AssertionError $exception) {
|
||||
goto development; // zend.assertions=1 and assert.exception=1, use development definition.
|
||||
}
|
||||
} // @codeCoverageIgnoreEnd
|
||||
|
@ -144,13 +144,23 @@ function capture(Awaitable $awaitable, $className, callable $functor) {
|
||||
*/
|
||||
function timeout(Awaitable $awaitable, $timeout) {
|
||||
$deferred = new Deferred;
|
||||
$resolved = false;
|
||||
|
||||
$watcher = Loop::delay($timeout, function () use ($deferred) {
|
||||
$deferred->fail(new TimeoutException);
|
||||
$watcher = Loop::delay($timeout, function () use (&$resolved, $deferred) {
|
||||
if (!$resolved) {
|
||||
$resolved = true;
|
||||
$deferred->fail(new TimeoutException);
|
||||
}
|
||||
});
|
||||
|
||||
$awaitable->when(function () use ($awaitable, $deferred, $watcher) {
|
||||
$awaitable->when(function () use (&$resolved, $awaitable, $deferred, $watcher) {
|
||||
Loop::cancel($watcher);
|
||||
|
||||
if ($resolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
$resolved = true;
|
||||
$deferred->resolve($awaitable);
|
||||
});
|
||||
|
||||
|
31
phpunit.xml.dist
Normal file
31
phpunit.xml.dist
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
|
||||
backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Amp">
|
||||
<directory>test</directory>
|
||||
<!-- Remove tags below once PHP 7.0 is required -->
|
||||
<exclude>test/ExtendedCoroutineTest.php</exclude>
|
||||
<file phpVersion="7.0.0">test/ExtendedCoroutineTest.php</file>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">lib</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<logging>
|
||||
<log type="coverage-html" target="build/coverage" title="Icicle" highlight="true"/>
|
||||
</logging>
|
||||
</phpunit>
|
105
test/AdaptTest.php
Normal file
105
test/AdaptTest.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp;
|
||||
use Amp\Failure;
|
||||
use Amp\Success;
|
||||
use Interop\Async\Awaitable;
|
||||
|
||||
class PromiseMock {
|
||||
/**
|
||||
* @var \Interop\Async\Awaitable
|
||||
*/
|
||||
private $awaitable;
|
||||
|
||||
public function __construct(Awaitable $awaitable) {
|
||||
$this->awaitable = $awaitable;
|
||||
}
|
||||
|
||||
public function then(callable $onFulfilled = null, callable $onRejected = null) {
|
||||
$this->awaitable->when(function ($exception, $value) use ($onFulfilled, $onRejected) {
|
||||
if ($exception) {
|
||||
if ($onRejected) {
|
||||
$onRejected($exception);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ($onFulfilled) {
|
||||
$onFulfilled($value);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class AdaptTest extends \PHPUnit_Framework_TestCase {
|
||||
public function testThenCalled() {
|
||||
$mock = $this->getMockBuilder(PromiseMock::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method("then")
|
||||
->with(
|
||||
$this->callback(function ($resolve) {
|
||||
return is_callable($resolve);
|
||||
}),
|
||||
$this->callback(function ($reject) {
|
||||
return is_callable($reject);
|
||||
})
|
||||
);
|
||||
|
||||
$awaitable = Amp\adapt($mock);
|
||||
|
||||
$this->assertInstanceOf(Awaitable::class, $awaitable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testThenCalled
|
||||
*/
|
||||
public function testAwaitableFulfilled() {
|
||||
$value = 1;
|
||||
|
||||
$promise = new PromiseMock(new Success($value));
|
||||
|
||||
$awaitable = Amp\adapt($promise);
|
||||
|
||||
$awaitable->when(function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
});
|
||||
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testThenCalled
|
||||
*/
|
||||
public function testAwaitableRejected() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$promise = new PromiseMock(new Failure($exception));
|
||||
|
||||
$awaitable = Amp\adapt($promise);
|
||||
|
||||
$awaitable->when(function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertSame($exception, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testScalarValue() {
|
||||
Amp\adapt(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testNonThenableObject() {
|
||||
Amp\adapt(new \stdClass);
|
||||
}
|
||||
}
|
77
test/AllTest.php
Normal file
77
test/AllTest.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp;
|
||||
use Amp\Pause;
|
||||
use Amp\Success;
|
||||
use Interop\Async\Loop;
|
||||
|
||||
class AllTest extends \PHPUnit_Framework_TestCase {
|
||||
public function testEmptyArray() {
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
Amp\all([])->when($callback);
|
||||
|
||||
$this->assertSame([], $result);
|
||||
}
|
||||
|
||||
public function testSuccessfulAwaitablesArray() {
|
||||
$awaitables = [new Success(1), new Success(2), new Success(3)];
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
Amp\all($awaitables)->when($callback);
|
||||
|
||||
$this->assertSame([1, 2, 3], $result);
|
||||
}
|
||||
|
||||
public function testPendingAwatiablesArray() {
|
||||
Loop::execute(function () use (&$result) {
|
||||
$awaitables = [
|
||||
new Pause(0.2, 1),
|
||||
new Pause(0.3, 2),
|
||||
new Pause(0.1, 3),
|
||||
];
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
Amp\all($awaitables)->when($callback);
|
||||
});
|
||||
|
||||
$this->assertEquals([1, 2, 3], $result);
|
||||
}
|
||||
|
||||
public function testArrayKeysPreserved() {
|
||||
$expected = ['one' => 1, 'two' => 2, 'three' => 3];
|
||||
|
||||
Loop::execute(function () use (&$result) {
|
||||
$awaitables = [
|
||||
'one' => new Pause(0.2, 1),
|
||||
'two' => new Pause(0.3, 2),
|
||||
'three' => new Pause(0.1, 3),
|
||||
];
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
Amp\all($awaitables)->when($callback);
|
||||
});
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testNonAwaitable() {
|
||||
Amp\all([1]);
|
||||
}
|
||||
}
|
113
test/CaptureTest.php
Normal file
113
test/CaptureTest.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp;
|
||||
use Amp\Failure;
|
||||
use Amp\Success;
|
||||
use Interop\Async\Awaitable;
|
||||
|
||||
class CaptureTest extends \PHPUnit_Framework_TestCase {
|
||||
public function testSuccessfulAwaitable() {
|
||||
$invoked = false;
|
||||
$callback = function ($exception) use (&$invoked) {
|
||||
$invoked = true;
|
||||
return -1;
|
||||
};
|
||||
|
||||
$value = 1;
|
||||
|
||||
$awaitable = new Success($value);
|
||||
|
||||
$awaitable = Amp\capture($awaitable, \Exception::class, $callback);
|
||||
$this->assertInstanceOf(Awaitable::class, $awaitable);
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
$awaitable->when($callback);
|
||||
|
||||
$this->assertFalse($invoked);
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
public function testFailedAwaitable() {
|
||||
$invoked = false;
|
||||
$callback = function ($exception) use (&$invoked, &$reason) {
|
||||
$invoked = true;
|
||||
$reason = $exception;
|
||||
return -1;
|
||||
};
|
||||
|
||||
$exception = new \Exception;
|
||||
|
||||
$awaitable = new Failure($exception);
|
||||
|
||||
$awaitable = Amp\capture($awaitable, \Exception::class, $callback);
|
||||
$this->assertInstanceOf(Awaitable::class, $awaitable);
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
$awaitable->when($callback);
|
||||
|
||||
$this->assertTrue($invoked);
|
||||
$this->assertSame($exception, $reason);
|
||||
$this->assertSame(-1, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testFailedAwaitable
|
||||
*/
|
||||
public function testCallbackThrowing() {
|
||||
$invoked = false;
|
||||
$callback = function ($exception) use (&$invoked) {
|
||||
$invoked = true;
|
||||
throw new \Exception;
|
||||
};
|
||||
|
||||
$exception = new \Exception;
|
||||
|
||||
$awaitable = new Failure($exception);
|
||||
|
||||
$awaitable = Amp\capture($awaitable, \Exception::class, $callback);
|
||||
|
||||
$callback = function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
};
|
||||
|
||||
$awaitable->when($callback);
|
||||
|
||||
$this->assertTrue($invoked);
|
||||
$this->assertNotSame($exception, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testFailedAwaitable
|
||||
*/
|
||||
public function testUnmatchedExceptionClass() {
|
||||
$invoked = false;
|
||||
$callback = function ($exception) use (&$invoked, &$reason) {
|
||||
$invoked = true;
|
||||
$reason = $exception;
|
||||
return -1;
|
||||
};
|
||||
|
||||
$exception = new \LogicException;
|
||||
|
||||
$awaitable = new Failure($exception);
|
||||
|
||||
$awaitable = Amp\capture($awaitable, \RuntimeException::class, $callback);
|
||||
|
||||
$callback = function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
};
|
||||
|
||||
$awaitable->when($callback);
|
||||
|
||||
$this->assertFalse($invoked);
|
||||
$this->assertSame($exception, $reason);
|
||||
}
|
||||
}
|
539
test/CoroutineTest.php
Normal file
539
test/CoroutineTest.php
Normal file
@ -0,0 +1,539 @@
|
||||
<?php
|
||||
|
||||
namespace Icicle\Tests\Coroutine;
|
||||
|
||||
use Amp;
|
||||
use Amp\Coroutine;
|
||||
use Amp\Failure;
|
||||
use Amp\InvalidYieldException;
|
||||
use Amp\Pause;
|
||||
use Amp\Success;
|
||||
use Interop\Async\Loop;
|
||||
|
||||
class CoroutineTest extends \PHPUnit_Framework_TestCase {
|
||||
const TIMEOUT = 0.1;
|
||||
|
||||
public function testYieldSuccessfulAwaitable() {
|
||||
$value = 1;
|
||||
|
||||
$generator = function () use (&$yielded, $value) {
|
||||
$yielded = (yield new Success($value));
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$this->assertSame($value, $yielded);
|
||||
}
|
||||
|
||||
public function testYieldFailedAwaitable() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$generator = function () use (&$yielded, $exception) {
|
||||
$yielded = (yield new Failure($exception));
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$this->assertNull($yielded);
|
||||
|
||||
$coroutine->when(function ($exception) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertSame($exception, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testYieldSuccessfulAwaitable
|
||||
*/
|
||||
public function testYieldPendingAwaitable() {
|
||||
$value = 1;
|
||||
|
||||
Loop::execute(function () use (&$yielded, $value) {
|
||||
$generator = function () use (&$yielded, $value) {
|
||||
$yielded = (yield new Pause(self::TIMEOUT, $value));
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
});
|
||||
|
||||
$this->assertSame($value, $yielded);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testYieldFailedAwaitable
|
||||
*/
|
||||
public function testCatchingFailedAwaitableException() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$fail = false;
|
||||
$generator = function () use (&$fail, &$result, $exception) {
|
||||
try {
|
||||
yield new Failure($exception);
|
||||
} catch (\Exception $exception) {
|
||||
$result = $exception;
|
||||
return;
|
||||
}
|
||||
|
||||
$fail = true;
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
if ($fail) {
|
||||
$this->fail("Failed awaitable reason not thrown into generator");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Remove once PHP 7 is required.
|
||||
*/
|
||||
public function testSucceedsWithCoroutineResult() {
|
||||
$value = 1;
|
||||
|
||||
$generator = function () use ($value) {
|
||||
yield Coroutine::result($value);
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
});
|
||||
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testSucceedsWithCoroutineResult
|
||||
* @todo Remove once PHP 7 is required.
|
||||
*/
|
||||
public function testSucceedsWithCoroutineAfterSuccessfulAwaitable() {
|
||||
$value = 1;
|
||||
|
||||
$generator = function () use ($value) {
|
||||
yield Coroutine::result(yield new Success($value));
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
});
|
||||
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testSucceedsWithCoroutineResult
|
||||
* @todo Remove once PHP 7 is required.
|
||||
*/
|
||||
public function testSucceedsWithCoroutineAfterFailedAwaitable() {
|
||||
$value = 1;
|
||||
|
||||
$generator = function () use ($value) {
|
||||
try {
|
||||
yield new Failure(new \Exception);
|
||||
} catch (\Exception $exception) {
|
||||
yield Coroutine::result($value);
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
});
|
||||
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
public function testInvalidYield() {
|
||||
$generator = function () {
|
||||
yield 1;
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertInstanceOf(InvalidYieldException::class, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testInvalidYield
|
||||
*/
|
||||
public function testInvalidYieldAfterYieldAwaitable() {
|
||||
$generator = function () {
|
||||
yield new Success;
|
||||
yield 1;
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertInstanceOf(InvalidYieldException::class, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testInvalidYield
|
||||
*/
|
||||
public function testCatchesExceptionAfterInvalidYield() {
|
||||
$generator = function () {
|
||||
try {
|
||||
yield 1;
|
||||
} catch (\Exception $exception) {
|
||||
yield Coroutine::result(1);
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertInstanceOf(InvalidYieldException::class, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testSucceedsWithCoroutineResult
|
||||
* @todo Remove once PHP 7 is required.
|
||||
*/
|
||||
public function testYieldsAfterCoroutineResult() {
|
||||
$generator = function () {
|
||||
yield Coroutine::result(1);
|
||||
yield new Success;
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertInstanceOf(InvalidYieldException::class, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testYieldsAfterCoroutineResult
|
||||
* @todo Remove once PHP 7 is required.
|
||||
*/
|
||||
public function testCatchesExceptionAfterInvalidResult() {
|
||||
$generator = function () {
|
||||
yield Coroutine::result(1);
|
||||
|
||||
try {
|
||||
yield new Success;
|
||||
} catch (\Exception $exception) {
|
||||
yield Coroutine::result(2);
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertInstanceOf(InvalidYieldException::class, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testInvalidYield
|
||||
*/
|
||||
public function testThrowAfterInvalidYield() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$generator = function () use ($exception) {
|
||||
try {
|
||||
yield 1;
|
||||
} catch (\Exception $reason) {
|
||||
throw $exception;
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertInstanceOf(InvalidYieldException::class, $reason);
|
||||
$this->assertSame($exception, $reason->getPrevious());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testYieldFailedAwaitable
|
||||
*/
|
||||
public function testCatchingFailedAwaitableExceptionWithNoFurtherYields() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$generator = function () use ($exception) {
|
||||
try {
|
||||
yield new Failure($exception);
|
||||
} catch (\Exception $exception) {
|
||||
// No further yields in generator.
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
});
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
public function testGeneratorThrowingExceptionFailsCoroutine() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$generator = function () use ($exception) {
|
||||
throw $exception;
|
||||
yield;
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertSame($exception, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testGeneratorThrowingExceptionFailsCoroutine
|
||||
*/
|
||||
public function testGeneratorThrowingExceptionWithFinallyFailsCoroutine() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$invoked = false;
|
||||
$generator = function () use (&$invoked, $exception) {
|
||||
try {
|
||||
throw $exception;
|
||||
yield;
|
||||
} finally {
|
||||
$invoked = true;
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertSame($exception, $reason);
|
||||
$this->assertTrue($invoked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testYieldFailedAwaitable
|
||||
* @depends testGeneratorThrowingExceptionWithFinallyFailsCoroutine
|
||||
*/
|
||||
public function testGeneratorYieldingFailedAwaitableWithFinallyFailsCoroutine() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$invoked = false;
|
||||
$generator = function () use (&$invoked, $exception) {
|
||||
try {
|
||||
yield new Failure($exception);
|
||||
} finally {
|
||||
$invoked = true;
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertSame($exception, $reason);
|
||||
$this->assertTrue($invoked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testGeneratorThrowingExceptionFailsCoroutine
|
||||
*/
|
||||
public function testGeneratorThrowingExceptionAfterPendingAwaitableWithFinallyFailsCoroutine() {
|
||||
$exception = new \Exception;
|
||||
$value = 1;
|
||||
|
||||
Loop::execute(function () use (&$yielded, &$invoked, &$reason, $exception, $value) {
|
||||
$invoked = false;
|
||||
$generator = function () use (&$yielded, &$invoked, $exception, $value) {
|
||||
try {
|
||||
$yielded = (yield new Pause(self::TIMEOUT, $value));
|
||||
throw $exception;
|
||||
} finally {
|
||||
$invoked = true;
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
});
|
||||
|
||||
$this->assertSame($exception, $reason);
|
||||
$this->assertTrue($invoked);
|
||||
$this->assertSame($value, $yielded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that yielding in a finally block is not recommended.
|
||||
*
|
||||
* @depends testYieldPendingAwaitable
|
||||
* @depends testGeneratorThrowingExceptionWithFinallyFailsCoroutine
|
||||
*/
|
||||
public function testGeneratorThrowingExceptionWithFinallyYieldingPendingAwaitable() {
|
||||
$exception = new \Exception;
|
||||
$value = 1;
|
||||
|
||||
Loop::execute(function () use (&$yielded, &$reason, $exception, $value) {
|
||||
$generator = function () use (&$yielded, $exception, $value) {
|
||||
try {
|
||||
throw $exception;
|
||||
} finally {
|
||||
$yielded = (yield new Pause(self::TIMEOUT, $value));
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
});
|
||||
|
||||
$this->assertSame($value, $yielded);
|
||||
$this->assertSame($exception, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testYieldPendingAwaitable
|
||||
* @depends testGeneratorThrowingExceptionWithFinallyFailsCoroutine
|
||||
*/
|
||||
public function testGeneratorThrowingExceptionWithFinallyBlockThrowing() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$generator = function () use ($exception) {
|
||||
try {
|
||||
throw new \Exception;
|
||||
} finally {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
yield; // Unreachable, but makes function a generator.
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
});
|
||||
|
||||
$this->assertSame($exception, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testYieldSuccessfulAwaitable
|
||||
*/
|
||||
public function testYieldConsecutiveSucceeded() {
|
||||
$invoked = false;
|
||||
Loop::execute(function () use (&$invoked) {
|
||||
$count = 1000;
|
||||
$awaitable = new Success;
|
||||
|
||||
$generator = function () use ($count, $awaitable) {
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
yield $awaitable;
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$invoked) {
|
||||
$invoked = true;
|
||||
});
|
||||
});
|
||||
|
||||
$this->assertTrue($invoked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testYieldFailedAwaitable
|
||||
*/
|
||||
public function testYieldConsecutiveFailed() {
|
||||
$invoked = false;
|
||||
Loop::execute(function () use (&$invoked) {
|
||||
$count = 1000;
|
||||
$awaitable = new Failure(new \Exception);
|
||||
|
||||
$generator = function () use ($count, $awaitable) {
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
try {
|
||||
yield $awaitable;
|
||||
} catch (\Exception $exception) {
|
||||
// Ignore and continue.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$invoked) {
|
||||
$invoked = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testYieldSuccessfulAwaitable
|
||||
*/
|
||||
public function testFastInvalidGenerator() {
|
||||
$generator = function () {
|
||||
if (false) {
|
||||
yield new Success;
|
||||
}
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$invoked = false;
|
||||
$coroutine->when(function ($exception, $value) use (&$invoked) {
|
||||
$invoked = true;
|
||||
});
|
||||
|
||||
$this->assertTrue($invoked);
|
||||
}
|
||||
|
||||
public function testCoroutineFunction() {
|
||||
$callable = Amp\coroutine(function () {
|
||||
yield;
|
||||
});
|
||||
|
||||
$this->assertInstanceOf(Coroutine::class, $callable());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCoroutineFunction
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testCoroutineFunctionWithNonGeneratorCallback() {
|
||||
$callable = Amp\coroutine(function () {});
|
||||
|
||||
$this->assertInstanceOf(Coroutine::class, $callable());
|
||||
}
|
||||
}
|
60
test/DeferredTest.php
Normal file
60
test/DeferredTest.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp\Deferred;
|
||||
use Interop\Async\Awaitable;
|
||||
|
||||
class DeferredTest extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @var \Amp\Deferred
|
||||
*/
|
||||
private $deferred;
|
||||
|
||||
public function setUp() {
|
||||
$this->deferred = new Deferred;
|
||||
}
|
||||
|
||||
public function testGetAwaitable() {
|
||||
$awaitable = $this->deferred->getAwaitable();
|
||||
$this->assertInstanceOf(Awaitable::class, $awaitable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testGetAwaitable
|
||||
*/
|
||||
public function testResolve() {
|
||||
$value = "Resolution value";
|
||||
$awaitable = $this->deferred->getAwaitable();
|
||||
|
||||
$invoked = false;
|
||||
$awaitable->when(function ($exception, $value) use (&$invoked, &$result) {
|
||||
$invoked = true;
|
||||
$result = $value;
|
||||
});
|
||||
|
||||
$this->deferred->resolve($value);
|
||||
|
||||
$this->assertTrue($invoked);
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testGetAwaitable
|
||||
*/
|
||||
public function testFail() {
|
||||
$exception = new \Exception;
|
||||
$awaitable = $this->deferred->getAwaitable();
|
||||
|
||||
$invoked = false;
|
||||
$awaitable->when(function ($exception, $value) use (&$invoked, &$result) {
|
||||
$invoked = true;
|
||||
$result = $exception;
|
||||
});
|
||||
|
||||
$this->deferred->fail($exception);
|
||||
|
||||
$this->assertTrue($invoked);
|
||||
$this->assertSame($exception, $result);
|
||||
}
|
||||
}
|
80
test/ExtendedCoroutineTest.php
Normal file
80
test/ExtendedCoroutineTest.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp\Coroutine;
|
||||
use Amp\Success;
|
||||
|
||||
/**
|
||||
* @todo Combine with CoroutineTest once PHP 7 is required.
|
||||
*/
|
||||
class ExtendedCoroutineTest extends \PHPUnit_Framework_TestCase {
|
||||
public function testCoroutineResolvedWithReturn() {
|
||||
$value = 1;
|
||||
|
||||
$generator = function () use ($value) {
|
||||
return $value;
|
||||
yield; // Unreachable, but makes function a coroutine.
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
});
|
||||
|
||||
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCoroutineResolvedWithReturn
|
||||
*/
|
||||
public function testYieldFromGenerator() {
|
||||
$value = 1;
|
||||
|
||||
$generator = function () use ($value) {
|
||||
$generator = function () use ($value) {
|
||||
return yield new Success($value);
|
||||
};
|
||||
|
||||
return yield from $generator();
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
});
|
||||
|
||||
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCoroutineResolvedWithReturn
|
||||
*/
|
||||
public function testFastReturningGenerator()
|
||||
{
|
||||
$value = 1;
|
||||
|
||||
$generator = function () use ($value) {
|
||||
if (true) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
yield;
|
||||
|
||||
return -$value;
|
||||
};
|
||||
|
||||
$coroutine = new Coroutine($generator());
|
||||
|
||||
$coroutine->when(function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
});
|
||||
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
}
|
57
test/FailureTest.php
Normal file
57
test/FailureTest.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp\Failure;
|
||||
use Interop\Async\Loop;
|
||||
|
||||
class FailureTest extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testConstructWithNonException() {
|
||||
$failure = new Failure(1);
|
||||
}
|
||||
|
||||
public function testWhen() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$invoked = 0;
|
||||
$callback = function ($exception, $value) use (&$invoked, &$reason) {
|
||||
++$invoked;
|
||||
$reason = $exception;
|
||||
};
|
||||
|
||||
$success = new Failure($exception);
|
||||
|
||||
$success->when($callback);
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
$this->assertSame($exception, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhen
|
||||
*/
|
||||
public function testWhenThrowingForwardsToLoopHandlerOnSuccess() {
|
||||
Loop::execute(function () use (&$invoked) {
|
||||
$invoked = 0;
|
||||
$expected = new \Exception;
|
||||
|
||||
Loop::setErrorHandler(function ($exception) use (&$invoked, $expected) {
|
||||
++$invoked;
|
||||
$this->assertSame($expected, $exception);
|
||||
});
|
||||
|
||||
$callback = function () use ($expected) {
|
||||
throw $expected;
|
||||
};
|
||||
|
||||
$success = new Failure(new \Exception);
|
||||
|
||||
$success->when($callback);
|
||||
});
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
}
|
||||
}
|
312
test/FutureTest.php
Normal file
312
test/FutureTest.php
Normal file
@ -0,0 +1,312 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp\Future;
|
||||
use Interop\Async\Awaitable;
|
||||
use Interop\Async\Loop;
|
||||
|
||||
class FutureTest extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @var \Amp\Future
|
||||
*/
|
||||
private $future;
|
||||
|
||||
public function setUp() {
|
||||
$this->future = new Future;
|
||||
}
|
||||
|
||||
public function testWhenOnSuccess() {
|
||||
$value = "Resolution value";
|
||||
|
||||
$invoked = 0;
|
||||
$callback = function ($exception, $value) use (&$invoked, &$result) {
|
||||
++$invoked;
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
$this->future->when($callback);
|
||||
|
||||
$this->future->resolve($value);
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhenOnSuccess
|
||||
*/
|
||||
public function testMultipleWhensOnSuccess() {
|
||||
$value = "Resolution value";
|
||||
|
||||
$invoked = 0;
|
||||
$callback = function ($exception, $value) use (&$invoked, &$result) {
|
||||
++$invoked;
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
$this->future->when($callback);
|
||||
$this->future->when($callback);
|
||||
$this->future->when($callback);
|
||||
|
||||
$this->future->resolve($value);
|
||||
|
||||
$this->assertSame(3, $invoked);
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhenOnSuccess
|
||||
*/
|
||||
public function testWhenAfterSuccess() {
|
||||
$value = "Resolution value";
|
||||
|
||||
$invoked = 0;
|
||||
$callback = function ($exception, $value) use (&$invoked, &$result) {
|
||||
++$invoked;
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
$this->future->resolve($value);
|
||||
|
||||
$this->future->when($callback);
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhenAfterSuccess
|
||||
*/
|
||||
public function testMultipleWhenAfterSuccess() {
|
||||
$value = "Resolution value";
|
||||
|
||||
$invoked = 0;
|
||||
$callback = function ($exception, $value) use (&$invoked, &$result) {
|
||||
++$invoked;
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
$this->future->resolve($value);
|
||||
|
||||
$this->future->when($callback);
|
||||
$this->future->when($callback);
|
||||
$this->future->when($callback);
|
||||
|
||||
$this->assertSame(3, $invoked);
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhenOnSuccess
|
||||
*/
|
||||
public function testWhenThrowingForwardsToLoopHandlerOnSuccess() {
|
||||
Loop::execute(function () use (&$invoked) {
|
||||
$invoked = 0;
|
||||
$expected = new \Exception;
|
||||
|
||||
Loop::setErrorHandler(function ($exception) use (&$invoked, $expected) {
|
||||
++$invoked;
|
||||
$this->assertSame($expected, $exception);
|
||||
});
|
||||
|
||||
$callback = function () use ($expected) {
|
||||
throw $expected;
|
||||
};
|
||||
|
||||
$this->future->when($callback);
|
||||
|
||||
$this->future->resolve($expected);
|
||||
});
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhenAfterSuccess
|
||||
*/
|
||||
public function testWhenThrowingForwardsToLoopHandlerAfterSuccess() {
|
||||
Loop::execute(function () use (&$invoked) {
|
||||
$invoked = 0;
|
||||
$expected = new \Exception;
|
||||
|
||||
Loop::setErrorHandler(function ($exception) use (&$invoked, $expected) {
|
||||
++$invoked;
|
||||
$this->assertSame($expected, $exception);
|
||||
});
|
||||
|
||||
$callback = function () use ($expected) {
|
||||
throw $expected;
|
||||
};
|
||||
|
||||
$this->future->resolve($expected);
|
||||
|
||||
$this->future->when($callback);
|
||||
});
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
}
|
||||
|
||||
public function testWhenOnFail() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$invoked = 0;
|
||||
$callback = function ($exception, $value) use (&$invoked, &$result) {
|
||||
++$invoked;
|
||||
$result = $exception;
|
||||
};
|
||||
|
||||
$this->future->when($callback);
|
||||
|
||||
$this->future->fail($exception);
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
$this->assertSame($exception, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhenOnFail
|
||||
*/
|
||||
public function testMultipleWhensOnFail() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$invoked = 0;
|
||||
$callback = function ($exception, $value) use (&$invoked, &$result) {
|
||||
++$invoked;
|
||||
$result = $exception;
|
||||
};
|
||||
|
||||
$this->future->when($callback);
|
||||
$this->future->when($callback);
|
||||
$this->future->when($callback);
|
||||
|
||||
$this->future->fail($exception);
|
||||
|
||||
$this->assertSame(3, $invoked);
|
||||
$this->assertSame($exception, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhenOnFail
|
||||
*/
|
||||
public function testWhenAfterFail() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$invoked = 0;
|
||||
$callback = function ($exception, $value) use (&$invoked, &$result) {
|
||||
++$invoked;
|
||||
$result = $exception;
|
||||
};
|
||||
|
||||
$this->future->fail($exception);
|
||||
|
||||
$this->future->when($callback);
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
$this->assertSame($exception, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhenAfterFail
|
||||
*/
|
||||
public function testMultipleWhensAfterFail() {
|
||||
$exception = new \Exception;
|
||||
|
||||
$invoked = 0;
|
||||
$callback = function ($exception, $value) use (&$invoked, &$result) {
|
||||
++$invoked;
|
||||
$result = $exception;
|
||||
};
|
||||
|
||||
$this->future->fail($exception);
|
||||
|
||||
$this->future->when($callback);
|
||||
$this->future->when($callback);
|
||||
$this->future->when($callback);
|
||||
|
||||
$this->assertSame(3, $invoked);
|
||||
$this->assertSame($exception, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhenOnSuccess
|
||||
*/
|
||||
public function testWhenThrowingForwardsToLoopHandlerOnFail() {
|
||||
Loop::execute(function () use (&$invoked) {
|
||||
$invoked = 0;
|
||||
$expected = new \Exception;
|
||||
|
||||
Loop::setErrorHandler(function ($exception) use (&$invoked, $expected) {
|
||||
++$invoked;
|
||||
$this->assertSame($expected, $exception);
|
||||
});
|
||||
|
||||
$callback = function () use ($expected) {
|
||||
throw $expected;
|
||||
};
|
||||
|
||||
$this->future->when($callback);
|
||||
|
||||
$this->future->fail(new \Exception);
|
||||
});
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhenOnSuccess
|
||||
*/
|
||||
public function testWhenThrowingForwardsToLoopHandlerAfterFail() {
|
||||
Loop::execute(function () use (&$invoked) {
|
||||
$invoked = 0;
|
||||
$expected = new \Exception;
|
||||
|
||||
Loop::setErrorHandler(function ($exception) use (&$invoked, $expected) {
|
||||
++$invoked;
|
||||
$this->assertSame($expected, $exception);
|
||||
});
|
||||
|
||||
$callback = function () use ($expected) {
|
||||
throw $expected;
|
||||
};
|
||||
|
||||
$this->future->fail(new \Exception);
|
||||
|
||||
$this->future->when($callback);
|
||||
});
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
}
|
||||
|
||||
public function testResolveWithAwaitableBeforeWhen() {
|
||||
$awaitable = $this->getMockBuilder(Awaitable::class)->getMock();
|
||||
|
||||
$awaitable->expects($this->once())
|
||||
->method("when")
|
||||
->with($this->callback("is_callable"));
|
||||
|
||||
$this->future->resolve($awaitable);
|
||||
|
||||
$this->future->when(function () {});
|
||||
}
|
||||
|
||||
public function testResolveWithAwaitableAfterWhen() {
|
||||
$awaitable = $this->getMockBuilder(Awaitable::class)->getMock();
|
||||
|
||||
$awaitable->expects($this->once())
|
||||
->method("when")
|
||||
->with($this->callback("is_callable"));
|
||||
|
||||
$this->future->when(function () {});
|
||||
|
||||
$this->future->resolve($awaitable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testDoubleResolve() {
|
||||
$this->future->resolve();
|
||||
$this->future->resolve();
|
||||
}
|
||||
}
|
84
test/PipeTest.php
Normal file
84
test/PipeTest.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp;
|
||||
use Amp\Failure;
|
||||
use Amp\Success;
|
||||
use Interop\Async\Awaitable;
|
||||
|
||||
class PipeTest extends \PHPUnit_Framework_TestCase {
|
||||
public function testSuccessfulAwaitable() {
|
||||
$invoked = false;
|
||||
$callback = function ($value) use (&$invoked) {
|
||||
$invoked = true;
|
||||
return $value + 1;
|
||||
};
|
||||
|
||||
$value = 1;
|
||||
|
||||
$awaitable = new Success($value);
|
||||
|
||||
$awaitable = Amp\pipe($awaitable, $callback);
|
||||
$this->assertInstanceOf(Awaitable::class, $awaitable);
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
$awaitable->when($callback);
|
||||
|
||||
$this->assertTrue($invoked);
|
||||
$this->assertSame($value + 1, $result);
|
||||
}
|
||||
|
||||
public function testFailedAwaitable() {
|
||||
$invoked = false;
|
||||
$callback = function ($value) use (&$invoked) {
|
||||
$invoked = true;
|
||||
return $value + 1;
|
||||
};
|
||||
|
||||
$exception = new \Exception;
|
||||
|
||||
$awaitable = new Failure($exception);
|
||||
|
||||
$awaitable = Amp\pipe($awaitable, $callback);
|
||||
$this->assertInstanceOf(Awaitable::class, $awaitable);
|
||||
|
||||
$callback = function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
};
|
||||
|
||||
$awaitable->when($callback);
|
||||
|
||||
$this->assertFalse($invoked);
|
||||
$this->assertSame($exception, $reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testSuccessfulAwaitable
|
||||
*/
|
||||
public function testCallbackThrowing() {
|
||||
$exception = new \Exception;
|
||||
$callback = function ($value) use (&$invoked, $exception) {
|
||||
$invoked = true;
|
||||
throw $exception;
|
||||
};
|
||||
|
||||
$value = 1;
|
||||
|
||||
$awaitable = new Success($value);
|
||||
|
||||
$awaitable = Amp\pipe($awaitable, $callback);
|
||||
|
||||
$callback = function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
};
|
||||
|
||||
$awaitable->when($callback);
|
||||
|
||||
$this->assertTrue($invoked);
|
||||
$this->assertSame($exception, $reason);
|
||||
}
|
||||
}
|
26
test/RethrowTest.php
Normal file
26
test/RethrowTest.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp;
|
||||
use Amp\Failure;
|
||||
use Interop\Async\Loop;
|
||||
|
||||
class RethrowTest extends \PHPUnit_Framework_TestCase {
|
||||
public function testWaitOnPendingAwaitable() {
|
||||
$exception = new \Exception;
|
||||
|
||||
try {
|
||||
Loop::execute(function () use ($exception) {
|
||||
$awaitable = new Failure($exception);
|
||||
|
||||
Amp\rethrow($awaitable);
|
||||
});
|
||||
} catch (\Exception $reason) {
|
||||
$this->assertSame($exception, $reason);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->fail('Failed awaitable reason should be thrown from loop');
|
||||
}
|
||||
}
|
106
test/SomeTest.php
Normal file
106
test/SomeTest.php
Normal file
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp;
|
||||
use Amp\Failure;
|
||||
use Amp\MultiReasonException;
|
||||
use Amp\Pause;
|
||||
use Amp\Success;
|
||||
use Interop\Async\Loop;
|
||||
|
||||
class SomeTest extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testEmptyArray() {
|
||||
Amp\some([], 1);
|
||||
}
|
||||
|
||||
public function testSuccessfulAwaitablesArray() {
|
||||
$awaitables = [new Success(1), new Success(2), new Success(3)];
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
Amp\some($awaitables, 2)->when($callback);
|
||||
|
||||
$this->assertSame([1, 2], $result);
|
||||
}
|
||||
|
||||
public function testSuccessfulAndFailedAwaitablesArray() {
|
||||
$awaitables = [new Failure(new \Exception), new Failure(new \Exception), new Success(3)];
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
Amp\some($awaitables, 1)->when($callback);
|
||||
|
||||
$this->assertSame([2 => 3], $result);
|
||||
}
|
||||
|
||||
public function testTooManyFailedAwaitables() {
|
||||
$awaitables = [new Failure(new \Exception), new Failure(new \Exception), new Success(3)];
|
||||
|
||||
$callback = function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
};
|
||||
|
||||
Amp\some($awaitables, 2)->when($callback);
|
||||
|
||||
$this->assertInstanceOf(MultiReasonException::class, $reason);
|
||||
|
||||
$reasons = $reason->getReasons();
|
||||
|
||||
foreach ($reasons as $reason) {
|
||||
$this->assertInstanceOf(\Exception::class, $reason);
|
||||
}
|
||||
}
|
||||
|
||||
public function testPendingAwatiablesArray() {
|
||||
Loop::execute(function () use (&$result) {
|
||||
$awaitables = [
|
||||
new Pause(0.2, 1),
|
||||
new Pause(0.3, 2),
|
||||
new Pause(0.1, 3),
|
||||
];
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
Amp\some($awaitables, 2)->when($callback);
|
||||
});
|
||||
|
||||
$this->assertEquals([0 => 1, 2 => 3], $result);
|
||||
}
|
||||
|
||||
public function testArrayKeysPreserved() {
|
||||
$expected = ['one' => 1, 'two' => 2, 'three' => 3];
|
||||
|
||||
Loop::execute(function () use (&$result) {
|
||||
$awaitables = [
|
||||
'one' => new Pause(0.2, 1),
|
||||
'two' => new Pause(0.3, 2),
|
||||
'three' => new Pause(0.1, 3),
|
||||
];
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
Amp\some($awaitables, 3)->when($callback);
|
||||
});
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testNonAwaitable() {
|
||||
Amp\some([1], 1);
|
||||
}
|
||||
}
|
58
test/SuccessTest.php
Normal file
58
test/SuccessTest.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp\Success;
|
||||
use Interop\Async\Awaitable;
|
||||
use Interop\Async\Loop;
|
||||
|
||||
class SuccessTest extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testConstructWithNonException() {
|
||||
$failure = new Success($this->getMockBuilder(Awaitable::class)->getMock());
|
||||
}
|
||||
|
||||
public function testWhen() {
|
||||
$value = "Resolution value";
|
||||
|
||||
$invoked = 0;
|
||||
$callback = function ($exception, $value) use (&$invoked, &$result) {
|
||||
++$invoked;
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
$success = new Success($value);
|
||||
|
||||
$success->when($callback);
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWhen
|
||||
*/
|
||||
public function testWhenThrowingForwardsToLoopHandlerOnSuccess() {
|
||||
Loop::execute(function () use (&$invoked) {
|
||||
$invoked = 0;
|
||||
$expected = new \Exception;
|
||||
|
||||
Loop::setErrorHandler(function ($exception) use (&$invoked, $expected) {
|
||||
++$invoked;
|
||||
$this->assertSame($expected, $exception);
|
||||
});
|
||||
|
||||
$callback = function () use ($expected) {
|
||||
throw $expected;
|
||||
};
|
||||
|
||||
$success = new Success;
|
||||
|
||||
$success->when($callback);
|
||||
});
|
||||
|
||||
$this->assertSame(1, $invoked);
|
||||
}
|
||||
}
|
92
test/TimeoutTest.php
Normal file
92
test/TimeoutTest.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp;
|
||||
use Amp\Failure;
|
||||
use Amp\Pause;
|
||||
use Amp\Success;
|
||||
use Interop\Async\Awaitable;
|
||||
use Interop\Async\Loop;
|
||||
|
||||
class TimeoutTest extends \PHPUnit_Framework_TestCase {
|
||||
public function testSuccessfulAwaitable() {
|
||||
Loop::execute(function () {
|
||||
$value = 1;
|
||||
|
||||
$awaitable = new Success($value);
|
||||
|
||||
$awaitable = Amp\timeout($awaitable, 100);
|
||||
$this->assertInstanceOf(Awaitable::class, $awaitable);
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
$awaitable->when($callback);
|
||||
|
||||
$this->assertSame($value, $result);
|
||||
});
|
||||
}
|
||||
|
||||
public function testFailedAwaitable() {
|
||||
Loop::execute(function () {
|
||||
$exception = new \Exception;
|
||||
|
||||
$awaitable = new Failure($exception);
|
||||
|
||||
$awaitable = Amp\timeout($awaitable, 100);
|
||||
$this->assertInstanceOf(Awaitable::class, $awaitable);
|
||||
|
||||
$callback = function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
};
|
||||
|
||||
$awaitable->when($callback);
|
||||
|
||||
$this->assertSame($exception, $reason);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testSuccessfulAwaitable
|
||||
*/
|
||||
public function testFastPending() {
|
||||
$value = 1;
|
||||
|
||||
Loop::execute(function () use (&$result, $value) {
|
||||
$awaitable = new Pause(50, $value);
|
||||
|
||||
$awaitable = Amp\timeout($awaitable, 100);
|
||||
$this->assertInstanceOf(Awaitable::class, $awaitable);
|
||||
|
||||
$callback = function ($exception, $value) use (&$result) {
|
||||
$result = $value;
|
||||
};
|
||||
|
||||
$awaitable->when($callback);
|
||||
});
|
||||
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testSuccessfulAwaitable
|
||||
*/
|
||||
public function testSlowPending() {
|
||||
Loop::execute(function () use (&$reason) {
|
||||
$awaitable = new Pause(200);
|
||||
|
||||
$awaitable = Amp\timeout($awaitable, 100);
|
||||
$this->assertInstanceOf(Awaitable::class, $awaitable);
|
||||
|
||||
$callback = function ($exception, $value) use (&$reason) {
|
||||
$reason = $exception;
|
||||
};
|
||||
|
||||
$awaitable->when($callback);
|
||||
});
|
||||
|
||||
$this->assertInstanceOf(Amp\TimeoutException::class, $reason);
|
||||
}
|
||||
}
|
65
test/WaitTest.php
Normal file
65
test/WaitTest.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp;
|
||||
use Amp\Failure;
|
||||
use Amp\Future;
|
||||
use Amp\Pause;
|
||||
use Amp\Success;
|
||||
use Interop\Async\Loop;
|
||||
|
||||
class WaitTest extends \PHPUnit_Framework_TestCase {
|
||||
public function testWaitOnSuccessfulAwaitable()
|
||||
{
|
||||
$value = 1;
|
||||
|
||||
$awaitable = new Success($value);
|
||||
|
||||
$result = Amp\wait($awaitable);
|
||||
|
||||
$this->assertSame($value, $result);
|
||||
}
|
||||
|
||||
public function testWaitOnFailedAwaitable()
|
||||
{
|
||||
$exception = new \Exception();
|
||||
|
||||
$awaitable = new Failure($exception);
|
||||
|
||||
try {
|
||||
$result = Amp\wait($awaitable);
|
||||
} catch (\Exception $e) {
|
||||
$this->assertSame($exception, $e);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->fail('Rejection exception should be thrown from wait().');
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWaitOnSuccessfulAwaitable
|
||||
*/
|
||||
public function testWaitOnPendingAwaitable()
|
||||
{
|
||||
Loop::execute(function () {
|
||||
$value = 1;
|
||||
|
||||
$awaitable = new Pause(100, $value);
|
||||
|
||||
$result = Amp\wait($awaitable);
|
||||
|
||||
$this->assertSame($value, $result);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testAwaitableWithNoResolutionPathThrowsException()
|
||||
{
|
||||
$awaitable = new Future;
|
||||
|
||||
$result = Amp\wait($awaitable);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user