Skip to content

Commit

Permalink
Release v1 (#5)
Browse files Browse the repository at this point in the history
* Add missing typehint

* Add missing typehint

* Add missing typehint

* Update dependencies

* Improve tests for FulfilledPromise

* Complete testing of FulfilledPromise class

* Test Waitable
  • Loading branch information
g105b authored Jan 15, 2021
1 parent 0075e66 commit 2a7e838
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 16 deletions.
22 changes: 11 additions & 11 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/DeferredInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function resolve($value = null):void;
* registered with the Promise's catch() function will be rejected
* with this reason.
*/
public function reject(Throwable $reason);
public function reject(Throwable $reason):void;

/**
* Assigns a callback as a task to perform to complete the deferred
Expand Down
2 changes: 1 addition & 1 deletion src/FulfilledPromise.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class FulfilledPromise implements PromiseInterface {
/** @param ?mixed $promiseOrValue */
public function __construct($promiseOrValue = null) {
if($promiseOrValue instanceof PromiseInterface) {
throw new PromiseException("A FulfilledPromise must be resolved with a concrete value, not a Promise.");
throw new FulfilledValueNotConcreteException(get_class($promiseOrValue));
}

$this->value = $promiseOrValue;
Expand Down
4 changes: 4 additions & 0 deletions src/FulfilledValueNotConcreteException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php
namespace Gt\Promise;

class FulfilledValueNotConcreteException extends PromiseException {}
4 changes: 4 additions & 0 deletions src/PromiseWaitTaskNotSetException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php
namespace Gt\Promise;

class PromiseWaitTaskNotSetException extends PromiseException {}
1 change: 1 addition & 0 deletions src/Resolvable.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use Http\Promise\Promise as HttpPromiseInterface;

trait Resolvable {
/** @param Promise|mixed $promiseOrValue */
private function resolve($promiseOrValue = null):PromiseInterface {
if ($promiseOrValue instanceof PromiseInterface) {
return $promiseOrValue;
Expand Down
17 changes: 14 additions & 3 deletions src/Waitable.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ public function setWaitTask(callable $task):void {
$this->waitTask = $task;
}

public function wait($unwrap = true) {
/** @param bool $unwrap */
public function wait($unwrap = true):mixed {
if(!isset($this->waitTask)) {
throw new PromiseException("Promise::wait() is only possible when a wait task is set");
throw new PromiseWaitTaskNotSetException();
}

/** @var PromiseInterface $promise */
/** @var Promise $promise */
$promise = $this;
if($unwrap && $this instanceof Promise) {
$promise = $this->unwrap($promise);
Expand All @@ -29,5 +30,15 @@ public function wait($unwrap = true) {
while($promise->getState() === HttpPromiseInterface::PENDING) {
call_user_func($this->waitTask);
}

if($unwrap) {
$resolvedValue = null;
$promise->then(function(mixed $value) use(&$resolvedValue):void {
$resolvedValue = $value;
});
return $resolvedValue;
}

return null;
}
}
87 changes: 87 additions & 0 deletions test/phpunit/FulfilledPromiseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php
namespace Gt\Promise\Test;

use Closure;
use Exception;
use Gt\Promise\FulfilledPromise;
use Gt\Promise\FulfilledValueNotConcreteException;
use Gt\Promise\Promise;
use Http\Promise\Promise as HttpPromiseInterface;
use PHPUnit\Framework\TestCase;
use TypeError;

class FulfilledPromiseTest extends TestCase {
public function testCanNotResolveWithPromise() {
$callback = fn()=>true;
$promise = new Promise($callback);
self::expectException(FulfilledValueNotConcreteException::class);
new FulfilledPromise($promise);
}

public function testDoNothingWithNullComplete() {
$message = "Test message";
$sut = new FulfilledPromise($message);
$exception = null;
try {
$sut->complete();
}
catch(Exception $exception) {}

self::assertNull($exception);
}

public function testCompleteWithPromise() {
$message = "Test message";

$promise = self::createMock(Promise::class);
$promise->expects(self::once())
->method("complete");
$callback = fn() => $promise;

$sut = new FulfilledPromise($message);
$sut->complete($callback);
}

public function testCatch() {
// Catch does nothing because a FulfilledPromise is already resolved.
$callCount = 0;
$callback = function() use(&$callCount) {
$callCount++;
};
$sut = new FulfilledPromise(true);
self::assertSame($sut, $sut->catch($callback));
self::assertEquals(0, $callCount);
}

public function testFinally() {
$callCount = 0;
$callback = function() use(&$callCount) {
$callCount++;
};

$message = "Test message";
$sut = new FulfilledPromise($message);
$sut->finally($callback);
self::assertEquals(1, $callCount);
}

public function testCompleteWithInvalidCallback() {
$callback = function(string $requiredStringParameter) {};

$sut = new FulfilledPromise("Callback should not have a required string parameter!");
$reasonArray = [];
$sut->finally($callback)->catch(function(\Throwable $reason) use (&$reasonArray) {
array_push($reasonArray, $reason);
});
self::assertCount(1, $reasonArray);
self::assertInstanceOf(TypeError::class, $reasonArray[0]);
}

public function testGetState() {
$sut = new FulfilledPromise();
self::assertEquals(
HttpPromiseInterface::FULFILLED,
$sut->getState()
);
}
}
63 changes: 63 additions & 0 deletions test/phpunit/WaitableTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php
namespace Gt\Promise\Test;

use Gt\Promise\Promise;
use Gt\Promise\PromiseWaitTaskNotSetException;
use PHPUnit\Framework\TestCase;

class WaitableTest extends TestCase {
public function testWait() {
$callCount = 0;
$resolveCallback = null;
$executor = function(callable $resolve, callable $reject) use(&$resolveCallback):void {
$resolveCallback = $resolve;
};
$resolvedValue = "Done!";
$sut = new Promise($executor);

$waitTask = function() use(&$callCount, $resolveCallback, $resolvedValue) {
if($callCount >= 10) {
call_user_func($resolveCallback, $resolvedValue);
}
else {
$callCount++;
}
};

$sut->setWaitTask($waitTask);
self::assertEquals($resolvedValue, $sut->wait());
self::assertEquals(10, $callCount);
}

public function testWaitNotUnwrapped() {
$callCount = 0;
$resolveCallback = null;
$executor = function(callable $resolve, callable $reject) use(&$resolveCallback):void {
$resolveCallback = $resolve;
};
$resolvedValue = "Done!";
$sut = new Promise($executor);

$waitTask = function() use(&$callCount, $resolveCallback, $resolvedValue) {
if($callCount >= 10) {
call_user_func($resolveCallback, $resolvedValue);
}
else {
$callCount++;
}
};

$sut->setWaitTask($waitTask);
self::assertNull($sut->wait(false));
self::assertEquals(10, $callCount);
}

public function testWaitWithNoWaitTask() {
$executor = function(callable $resolve, callable $reject) use(&$resolveCallback):void {
$resolveCallback = $resolve;
};
$sut = new Promise($executor);;
self::expectException(PromiseWaitTaskNotSetException::class);
$sut->wait();
}
}

0 comments on commit 2a7e838

Please sign in to comment.