Skip to content

Commit 2a7e838

Browse files
author
Greg Bowler
authored
Release v1 (#5)
* Add missing typehint * Add missing typehint * Add missing typehint * Update dependencies * Improve tests for FulfilledPromise * Complete testing of FulfilledPromise class * Test Waitable
1 parent 0075e66 commit 2a7e838

9 files changed

+186
-16
lines changed

composer.lock

+11-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/DeferredInterface.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function resolve($value = null):void;
2727
* registered with the Promise's catch() function will be rejected
2828
* with this reason.
2929
*/
30-
public function reject(Throwable $reason);
30+
public function reject(Throwable $reason):void;
3131

3232
/**
3333
* Assigns a callback as a task to perform to complete the deferred

src/FulfilledPromise.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class FulfilledPromise implements PromiseInterface {
1515
/** @param ?mixed $promiseOrValue */
1616
public function __construct($promiseOrValue = null) {
1717
if($promiseOrValue instanceof PromiseInterface) {
18-
throw new PromiseException("A FulfilledPromise must be resolved with a concrete value, not a Promise.");
18+
throw new FulfilledValueNotConcreteException(get_class($promiseOrValue));
1919
}
2020

2121
$this->value = $promiseOrValue;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
namespace Gt\Promise;
3+
4+
class FulfilledValueNotConcreteException extends PromiseException {}
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
namespace Gt\Promise;
3+
4+
class PromiseWaitTaskNotSetException extends PromiseException {}

src/Resolvable.php

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use Http\Promise\Promise as HttpPromiseInterface;
55

66
trait Resolvable {
7+
/** @param Promise|mixed $promiseOrValue */
78
private function resolve($promiseOrValue = null):PromiseInterface {
89
if ($promiseOrValue instanceof PromiseInterface) {
910
return $promiseOrValue;

src/Waitable.php

+14-3
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ public function setWaitTask(callable $task):void {
1515
$this->waitTask = $task;
1616
}
1717

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

23-
/** @var PromiseInterface $promise */
24+
/** @var Promise $promise */
2425
$promise = $this;
2526
if($unwrap && $this instanceof Promise) {
2627
$promise = $this->unwrap($promise);
@@ -29,5 +30,15 @@ public function wait($unwrap = true) {
2930
while($promise->getState() === HttpPromiseInterface::PENDING) {
3031
call_user_func($this->waitTask);
3132
}
33+
34+
if($unwrap) {
35+
$resolvedValue = null;
36+
$promise->then(function(mixed $value) use(&$resolvedValue):void {
37+
$resolvedValue = $value;
38+
});
39+
return $resolvedValue;
40+
}
41+
42+
return null;
3243
}
3344
}

test/phpunit/FulfilledPromiseTest.php

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
namespace Gt\Promise\Test;
3+
4+
use Closure;
5+
use Exception;
6+
use Gt\Promise\FulfilledPromise;
7+
use Gt\Promise\FulfilledValueNotConcreteException;
8+
use Gt\Promise\Promise;
9+
use Http\Promise\Promise as HttpPromiseInterface;
10+
use PHPUnit\Framework\TestCase;
11+
use TypeError;
12+
13+
class FulfilledPromiseTest extends TestCase {
14+
public function testCanNotResolveWithPromise() {
15+
$callback = fn()=>true;
16+
$promise = new Promise($callback);
17+
self::expectException(FulfilledValueNotConcreteException::class);
18+
new FulfilledPromise($promise);
19+
}
20+
21+
public function testDoNothingWithNullComplete() {
22+
$message = "Test message";
23+
$sut = new FulfilledPromise($message);
24+
$exception = null;
25+
try {
26+
$sut->complete();
27+
}
28+
catch(Exception $exception) {}
29+
30+
self::assertNull($exception);
31+
}
32+
33+
public function testCompleteWithPromise() {
34+
$message = "Test message";
35+
36+
$promise = self::createMock(Promise::class);
37+
$promise->expects(self::once())
38+
->method("complete");
39+
$callback = fn() => $promise;
40+
41+
$sut = new FulfilledPromise($message);
42+
$sut->complete($callback);
43+
}
44+
45+
public function testCatch() {
46+
// Catch does nothing because a FulfilledPromise is already resolved.
47+
$callCount = 0;
48+
$callback = function() use(&$callCount) {
49+
$callCount++;
50+
};
51+
$sut = new FulfilledPromise(true);
52+
self::assertSame($sut, $sut->catch($callback));
53+
self::assertEquals(0, $callCount);
54+
}
55+
56+
public function testFinally() {
57+
$callCount = 0;
58+
$callback = function() use(&$callCount) {
59+
$callCount++;
60+
};
61+
62+
$message = "Test message";
63+
$sut = new FulfilledPromise($message);
64+
$sut->finally($callback);
65+
self::assertEquals(1, $callCount);
66+
}
67+
68+
public function testCompleteWithInvalidCallback() {
69+
$callback = function(string $requiredStringParameter) {};
70+
71+
$sut = new FulfilledPromise("Callback should not have a required string parameter!");
72+
$reasonArray = [];
73+
$sut->finally($callback)->catch(function(\Throwable $reason) use (&$reasonArray) {
74+
array_push($reasonArray, $reason);
75+
});
76+
self::assertCount(1, $reasonArray);
77+
self::assertInstanceOf(TypeError::class, $reasonArray[0]);
78+
}
79+
80+
public function testGetState() {
81+
$sut = new FulfilledPromise();
82+
self::assertEquals(
83+
HttpPromiseInterface::FULFILLED,
84+
$sut->getState()
85+
);
86+
}
87+
}

test/phpunit/WaitableTest.php

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
namespace Gt\Promise\Test;
3+
4+
use Gt\Promise\Promise;
5+
use Gt\Promise\PromiseWaitTaskNotSetException;
6+
use PHPUnit\Framework\TestCase;
7+
8+
class WaitableTest extends TestCase {
9+
public function testWait() {
10+
$callCount = 0;
11+
$resolveCallback = null;
12+
$executor = function(callable $resolve, callable $reject) use(&$resolveCallback):void {
13+
$resolveCallback = $resolve;
14+
};
15+
$resolvedValue = "Done!";
16+
$sut = new Promise($executor);
17+
18+
$waitTask = function() use(&$callCount, $resolveCallback, $resolvedValue) {
19+
if($callCount >= 10) {
20+
call_user_func($resolveCallback, $resolvedValue);
21+
}
22+
else {
23+
$callCount++;
24+
}
25+
};
26+
27+
$sut->setWaitTask($waitTask);
28+
self::assertEquals($resolvedValue, $sut->wait());
29+
self::assertEquals(10, $callCount);
30+
}
31+
32+
public function testWaitNotUnwrapped() {
33+
$callCount = 0;
34+
$resolveCallback = null;
35+
$executor = function(callable $resolve, callable $reject) use(&$resolveCallback):void {
36+
$resolveCallback = $resolve;
37+
};
38+
$resolvedValue = "Done!";
39+
$sut = new Promise($executor);
40+
41+
$waitTask = function() use(&$callCount, $resolveCallback, $resolvedValue) {
42+
if($callCount >= 10) {
43+
call_user_func($resolveCallback, $resolvedValue);
44+
}
45+
else {
46+
$callCount++;
47+
}
48+
};
49+
50+
$sut->setWaitTask($waitTask);
51+
self::assertNull($sut->wait(false));
52+
self::assertEquals(10, $callCount);
53+
}
54+
55+
public function testWaitWithNoWaitTask() {
56+
$executor = function(callable $resolve, callable $reject) use(&$resolveCallback):void {
57+
$resolveCallback = $resolve;
58+
};
59+
$sut = new Promise($executor);;
60+
self::expectException(PromiseWaitTaskNotSetException::class);
61+
$sut->wait();
62+
}
63+
}

0 commit comments

Comments
 (0)