Skip to content

Commit

Permalink
Fail test if returned promise or coroutine does not resolve
Browse files Browse the repository at this point in the history
  • Loading branch information
trowski committed Sep 18, 2019
1 parent 1986104 commit 2dd5fd8
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 11 deletions.
27 changes: 16 additions & 11 deletions src/AsyncTestCase.php
Expand Up @@ -49,27 +49,32 @@ final public function runAsyncTest(...$args)
));
}

$invoked = false;
$returnValue = null;

$start = \microtime(true);

Loop::run(function () use (&$returnValue, &$exception, $args) {
try {
$returnValue = yield call([$this, $this->realTestName], ...$args);
} catch (\Throwable $exception) {
// Also catches exception from potential nested loop.
// Exception is rethrown after Loop::run().
} finally {
if (isset($this->timeoutId)) {
Loop::cancel($this->timeoutId);
}
}
Loop::run(function () use (&$returnValue, &$exception, &$invoked, $args) {
$promise = call([$this, $this->realTestName], ...$args);
$promise->onResolve(function ($error, $value) use (&$invoked, &$exception, &$returnValue) {
$invoked = true;
$exception = $error;
$returnValue = $value;
});
});

if (isset($this->timeoutId)) {
Loop::cancel($this->timeoutId);
}

if (isset($exception)) {
throw $exception;
}

if (!$invoked) {
$this->fail('Loop stopped without resolving promise or coroutine returned from test method');
}

if ($this->minimumRuntime > 0) {
$actualRuntime = (int) (\round(\microtime(true) - $start, self::RUNTIME_PRECISION) * 1000);
$msg = 'Expected test to take at least %dms but instead took %dms';
Expand Down
24 changes: 24 additions & 0 deletions test/AsyncTestCaseTest.php
Expand Up @@ -98,6 +98,12 @@ public function testArgumentSupport(string $foo, int $bar, bool $baz)
}

public function testSetTimeout(): \Generator
{
$this->setTimeout(100);
$this->assertNull(yield new Delayed(50));
}

public function testSetTimeoutWithCoroutine(): \Generator
{
$this->setTimeout(100);

Expand All @@ -107,6 +113,16 @@ public function testSetTimeout(): \Generator
yield new Delayed(200);
}

public function testSetTimeoutWithWatcher()
{
$this->setTimeout(100);

$this->expectException(AssertionFailedError::class);
$this->expectExceptionMessage('Expected test to complete before 100ms time limit');

Loop::delay(200, function () {});
}

public function testSetMinimumRunTime(): \Generator
{
$this->setMinimumRuntime(100);
Expand All @@ -126,6 +142,14 @@ public function testSetMinimumRunTimeWithWatchersOnly()
Loop::delay(100, $this->createCallback(1));
}

public function testUnresolvedPromise(): Promise
{
$this->expectException(AssertionFailedError::class);
$this->expectExceptionMessage('Loop stopped without resolving promise or coroutine returned from test method');

return (new Deferred)->promise();
}

public function testCreateCallback()
{
$mock = $this->createCallback(1, function (int $value): int {
Expand Down

0 comments on commit 2dd5fd8

Please sign in to comment.