graphql-php/tests/Executor/Promise/SyncPromiseTest.php

425 lines
15 KiB
PHP
Raw Normal View History

<?php
2018-09-01 18:07:06 +03:00
declare(strict_types=1);
namespace GraphQL\Tests\Executor\Promise;
2018-09-26 12:07:23 +03:00
use Exception;
use GraphQL\Executor\Promise\Adapter\SyncPromise;
2018-07-29 18:43:10 +03:00
use PHPUnit\Framework\Error\Error;
use PHPUnit\Framework\TestCase;
2018-09-26 12:07:23 +03:00
use Throwable;
2018-09-01 18:07:06 +03:00
use function uniqid;
2018-07-29 18:43:10 +03:00
class SyncPromiseTest extends TestCase
{
public function getFulfilledPromiseResolveData()
{
2018-09-26 12:07:23 +03:00
$onFulfilledReturnsNull = static function () {
return null;
};
2018-09-01 18:07:06 +03:00
2018-09-26 12:07:23 +03:00
$onFulfilledReturnsSameValue = static function ($value) {
return $value;
};
2018-09-01 18:07:06 +03:00
2018-09-26 12:07:23 +03:00
$onFulfilledReturnsOtherValue = static function ($value) {
return 'other-' . $value;
};
2018-09-01 18:07:06 +03:00
2018-09-26 12:07:23 +03:00
$onFulfilledThrows = static function ($value) {
throw new Exception('onFulfilled throws this!');
};
return [
// $resolvedValue, $onFulfilled, $expectedNextValue, $expectedNextReason, $expectedNextState
['test-value', null, 'test-value', null, SyncPromise::FULFILLED],
[uniqid(), $onFulfilledReturnsNull, null, null, SyncPromise::FULFILLED],
['test-value', $onFulfilledReturnsSameValue, 'test-value', null, SyncPromise::FULFILLED],
['test-value-2', $onFulfilledReturnsOtherValue, 'other-test-value-2', null, SyncPromise::FULFILLED],
2018-09-01 18:07:06 +03:00
['test-value-3', $onFulfilledThrows, null, 'onFulfilled throws this!', SyncPromise::REJECTED],
];
}
/**
* @dataProvider getFulfilledPromiseResolveData
*/
public function testFulfilledPromiseCannotChangeValue(
$resolvedValue,
$onFulfilled,
$expectedNextValue,
$expectedNextReason,
$expectedNextState
2018-09-01 18:07:06 +03:00
) {
$promise = new SyncPromise();
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::PENDING, $promise->state);
$promise->resolve($resolvedValue);
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::FULFILLED, $promise->state);
2018-09-26 12:07:23 +03:00
$this->expectException(Throwable::class);
2018-07-29 18:43:10 +03:00
$this->expectExceptionMessage('Cannot change value of fulfilled promise');
$promise->resolve($resolvedValue . '-other-value');
}
/**
* @dataProvider getFulfilledPromiseResolveData
*/
public function testFulfilledPromiseCannotBeRejected(
$resolvedValue,
$onFulfilled,
$expectedNextValue,
$expectedNextReason,
$expectedNextState
2018-09-01 18:07:06 +03:00
) {
$promise = new SyncPromise();
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::PENDING, $promise->state);
$promise->resolve($resolvedValue);
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::FULFILLED, $promise->state);
2018-09-26 12:07:23 +03:00
$this->expectException(Throwable::class);
2018-07-29 18:43:10 +03:00
$this->expectExceptionMessage('Cannot reject fulfilled promise');
2018-09-26 12:07:23 +03:00
$promise->reject(new Exception('anything'));
}
/**
* @dataProvider getFulfilledPromiseResolveData
*/
public function testFulfilledPromise(
$resolvedValue,
$onFulfilled,
$expectedNextValue,
$expectedNextReason,
$expectedNextState
2018-09-01 18:07:06 +03:00
) {
$promise = new SyncPromise();
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::PENDING, $promise->state);
$promise->resolve($resolvedValue);
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::FULFILLED, $promise->state);
2018-09-01 18:07:06 +03:00
$nextPromise = $promise->then(
null,
2018-09-26 12:07:23 +03:00
static function () {
2018-09-01 18:07:06 +03:00
}
);
2018-09-19 18:12:09 +03:00
self::assertSame($promise, $nextPromise);
$onRejectedCalled = false;
2018-09-01 18:07:06 +03:00
$nextPromise = $promise->then(
$onFulfilled,
2018-09-26 12:07:23 +03:00
static function () use (&$onRejectedCalled) {
2018-09-01 18:07:06 +03:00
$onRejectedCalled = true;
}
);
if ($onFulfilled) {
2018-09-19 18:12:09 +03:00
self::assertNotSame($promise, $nextPromise);
self::assertEquals(SyncPromise::PENDING, $nextPromise->state);
} else {
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::FULFILLED, $nextPromise->state);
}
2018-09-19 18:12:09 +03:00
self::assertEquals(false, $onRejectedCalled);
2018-09-19 18:12:09 +03:00
self::assertValidPromise($nextPromise, $expectedNextReason, $expectedNextValue, $expectedNextState);
$nextPromise2 = $promise->then($onFulfilled);
$nextPromise3 = $promise->then($onFulfilled);
if ($onFulfilled) {
2018-09-19 18:12:09 +03:00
self::assertNotSame($nextPromise, $nextPromise2);
}
SyncPromise::runQueue();
2018-09-19 18:12:09 +03:00
self::assertValidPromise($nextPromise2, $expectedNextReason, $expectedNextValue, $expectedNextState);
self::assertValidPromise($nextPromise3, $expectedNextReason, $expectedNextValue, $expectedNextState);
}
2018-09-19 18:12:09 +03:00
private static function assertValidPromise(
2018-09-01 18:07:06 +03:00
SyncPromise $promise,
$expectedNextReason,
$expectedNextValue,
$expectedNextState
2018-09-19 18:12:09 +03:00
) : void {
2018-09-01 18:07:06 +03:00
$actualNextValue = null;
$actualNextReason = null;
$onFulfilledCalled = false;
$onRejectedCalled = false;
$promise->then(
2018-09-19 18:12:09 +03:00
static function ($nextValue) use (&$actualNextValue, &$onFulfilledCalled) {
2018-09-01 18:07:06 +03:00
$onFulfilledCalled = true;
$actualNextValue = $nextValue;
},
2018-09-26 12:07:23 +03:00
static function (Throwable $reason) use (&$actualNextReason, &$onRejectedCalled) {
2018-09-01 18:07:06 +03:00
$onRejectedCalled = true;
$actualNextReason = $reason->getMessage();
}
);
2018-09-19 18:12:09 +03:00
self::assertEquals($onFulfilledCalled, false);
self::assertEquals($onRejectedCalled, false);
2018-09-01 18:07:06 +03:00
SyncPromise::runQueue();
2018-09-19 18:12:09 +03:00
self::assertEquals(! $expectedNextReason, $onFulfilledCalled);
self::assertEquals(! ! $expectedNextReason, $onRejectedCalled);
2018-09-01 18:07:06 +03:00
2018-09-19 18:12:09 +03:00
self::assertEquals($expectedNextValue, $actualNextValue);
self::assertEquals($expectedNextReason, $actualNextReason);
self::assertEquals($expectedNextState, $promise->state);
2018-09-01 18:07:06 +03:00
}
public function getRejectedPromiseData()
{
2018-09-26 12:07:23 +03:00
$onRejectedReturnsNull = static function () {
return null;
};
2018-09-01 18:07:06 +03:00
2018-09-26 12:07:23 +03:00
$onRejectedReturnsSomeValue = static function ($reason) {
return 'some-value';
};
2018-09-01 18:07:06 +03:00
2018-09-26 12:07:23 +03:00
$onRejectedThrowsSameReason = static function ($reason) {
throw $reason;
};
2018-09-01 18:07:06 +03:00
2018-09-26 12:07:23 +03:00
$onRejectedThrowsOtherReason = static function ($value) {
throw new Exception('onRejected throws other!');
};
return [
// $rejectedReason, $onRejected, $expectedNextValue, $expectedNextReason, $expectedNextState
2018-09-26 12:07:23 +03:00
[new Exception('test-reason'), null, null, 'test-reason', SyncPromise::REJECTED],
[new Exception('test-reason-2'), $onRejectedReturnsNull, null, null, SyncPromise::FULFILLED],
[new Exception('test-reason-3'), $onRejectedReturnsSomeValue, 'some-value', null, SyncPromise::FULFILLED],
[new Exception('test-reason-4'), $onRejectedThrowsSameReason, null, 'test-reason-4', SyncPromise::REJECTED],
[new Exception('test-reason-5'), $onRejectedThrowsOtherReason, null, 'onRejected throws other!', SyncPromise::REJECTED],
];
}
/**
* @dataProvider getRejectedPromiseData
*/
public function testRejectedPromiseCannotChangeReason(
$rejectedReason,
$onRejected,
$expectedNextValue,
$expectedNextReason,
$expectedNextState
2018-09-01 18:07:06 +03:00
) {
$promise = new SyncPromise();
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::PENDING, $promise->state);
$promise->reject($rejectedReason);
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::REJECTED, $promise->state);
2018-09-26 12:07:23 +03:00
$this->expectException(Throwable::class);
2018-07-29 18:43:10 +03:00
$this->expectExceptionMessage('Cannot change rejection reason');
2018-09-26 12:07:23 +03:00
$promise->reject(new Exception('other-reason'));
}
/**
* @dataProvider getRejectedPromiseData
*/
public function testRejectedPromiseCannotBeResolved(
$rejectedReason,
$onRejected,
$expectedNextValue,
$expectedNextReason,
$expectedNextState
2018-09-01 18:07:06 +03:00
) {
$promise = new SyncPromise();
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::PENDING, $promise->state);
$promise->reject($rejectedReason);
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::REJECTED, $promise->state);
2018-09-26 12:07:23 +03:00
$this->expectException(Throwable::class);
2018-07-29 18:43:10 +03:00
$this->expectExceptionMessage('Cannot resolve rejected promise');
$promise->resolve('anything');
}
/**
* @dataProvider getRejectedPromiseData
*/
public function testRejectedPromise(
$rejectedReason,
$onRejected,
$expectedNextValue,
$expectedNextReason,
$expectedNextState
2018-09-01 18:07:06 +03:00
) {
$promise = new SyncPromise();
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::PENDING, $promise->state);
$promise->reject($rejectedReason);
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::REJECTED, $promise->state);
try {
2018-09-26 12:07:23 +03:00
$promise->reject(new Exception('other-reason'));
$this->fail('Expected exception not thrown');
2018-09-26 12:07:23 +03:00
} catch (Throwable $e) {
2018-09-19 18:12:09 +03:00
self::assertEquals('Cannot change rejection reason', $e->getMessage());
}
try {
$promise->resolve('anything');
$this->fail('Expected exception not thrown');
2018-09-26 12:07:23 +03:00
} catch (Throwable $e) {
2018-09-19 18:12:09 +03:00
self::assertEquals('Cannot resolve rejected promise', $e->getMessage());
}
2018-09-01 18:07:06 +03:00
$nextPromise = $promise->then(
2018-09-26 12:07:23 +03:00
static function () {
2018-09-01 18:07:06 +03:00
},
null
);
2018-09-19 18:12:09 +03:00
self::assertSame($promise, $nextPromise);
$onFulfilledCalled = false;
2018-09-01 18:07:06 +03:00
$nextPromise = $promise->then(
2018-09-26 12:07:23 +03:00
static function () use (&$onFulfilledCalled) {
$onFulfilledCalled = true;
},
$onRejected
);
if ($onRejected) {
2018-09-19 18:12:09 +03:00
self::assertNotSame($promise, $nextPromise);
self::assertEquals(SyncPromise::PENDING, $nextPromise->state);
} else {
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::REJECTED, $nextPromise->state);
}
2018-09-19 18:12:09 +03:00
self::assertEquals(false, $onFulfilledCalled);
self::assertValidPromise($nextPromise, $expectedNextReason, $expectedNextValue, $expectedNextState);
$nextPromise2 = $promise->then(null, $onRejected);
$nextPromise3 = $promise->then(null, $onRejected);
if ($onRejected) {
2018-09-19 18:12:09 +03:00
self::assertNotSame($nextPromise, $nextPromise2);
}
SyncPromise::runQueue();
2018-09-19 18:12:09 +03:00
self::assertValidPromise($nextPromise2, $expectedNextReason, $expectedNextValue, $expectedNextState);
self::assertValidPromise($nextPromise3, $expectedNextReason, $expectedNextValue, $expectedNextState);
}
public function testPendingPromise() : void
{
$promise = new SyncPromise();
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::PENDING, $promise->state);
try {
$promise->resolve($promise);
$this->fail('Expected exception not thrown');
2018-09-26 12:07:23 +03:00
} catch (Throwable $e) {
2018-09-19 18:12:09 +03:00
self::assertEquals('Cannot resolve promise with self', $e->getMessage());
self::assertEquals(SyncPromise::PENDING, $promise->state);
}
// Try to resolve with other promise (must resolve when other promise resolves)
$otherPromise = new SyncPromise();
$promise->resolve($otherPromise);
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::PENDING, $promise->state);
self::assertEquals(SyncPromise::PENDING, $otherPromise->state);
$otherPromise->resolve('the value');
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::FULFILLED, $otherPromise->state);
self::assertEquals(SyncPromise::PENDING, $promise->state);
self::assertValidPromise($promise, null, 'the value', SyncPromise::FULFILLED);
$promise = new SyncPromise();
$promise->resolve('resolved!');
2018-09-19 18:12:09 +03:00
self::assertValidPromise($promise, null, 'resolved!', SyncPromise::FULFILLED);
// Test rejections
$promise = new SyncPromise();
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::PENDING, $promise->state);
try {
$promise->reject('a');
$this->fail('Expected exception not thrown');
2018-07-29 18:43:10 +03:00
} catch (Error $e) {
throw $e;
2018-09-26 12:07:23 +03:00
} catch (Throwable $e) {
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::PENDING, $promise->state);
}
2018-09-26 12:07:23 +03:00
$promise->reject(new Exception('Rejected Reason'));
2018-09-19 18:12:09 +03:00
self::assertValidPromise($promise, 'Rejected Reason', null, SyncPromise::REJECTED);
2018-09-01 18:07:06 +03:00
$promise = new SyncPromise();
$promise2 = $promise->then(
null,
2018-09-26 12:07:23 +03:00
static function () {
2018-09-01 18:07:06 +03:00
return 'value';
}
);
2018-09-26 12:07:23 +03:00
$promise->reject(new Exception('Rejected Again'));
2018-09-19 18:12:09 +03:00
self::assertValidPromise($promise2, null, 'value', SyncPromise::FULFILLED);
2018-09-01 18:07:06 +03:00
$promise = new SyncPromise();
$promise2 = $promise->then();
2018-09-26 12:07:23 +03:00
$promise->reject(new Exception('Rejected Once Again'));
2018-09-19 18:12:09 +03:00
self::assertValidPromise($promise2, 'Rejected Once Again', null, SyncPromise::REJECTED);
}
public function testPendingPromiseThen() : void
{
$promise = new SyncPromise();
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::PENDING, $promise->state);
$nextPromise = $promise->then();
2018-09-19 18:12:09 +03:00
self::assertNotSame($promise, $nextPromise);
self::assertEquals(SyncPromise::PENDING, $promise->state);
self::assertEquals(SyncPromise::PENDING, $nextPromise->state);
// Make sure that it queues derivative promises until resolution:
$onFulfilledCount = 0;
2018-09-01 18:07:06 +03:00
$onRejectedCount = 0;
2018-09-26 12:07:23 +03:00
$onFulfilled = static function ($value) use (&$onFulfilledCount) {
$onFulfilledCount++;
2018-09-01 18:07:06 +03:00
return $onFulfilledCount;
};
2018-09-01 18:07:06 +03:00
2018-09-26 12:07:23 +03:00
$onRejected = static function ($reason) use (&$onRejectedCount) {
$onRejectedCount++;
throw $reason;
};
$nextPromise2 = $promise->then($onFulfilled, $onRejected);
$nextPromise3 = $promise->then($onFulfilled, $onRejected);
$nextPromise4 = $promise->then($onFulfilled, $onRejected);
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::getQueue()->count(), 0);
self::assertEquals($onFulfilledCount, 0);
self::assertEquals($onRejectedCount, 0);
$promise->resolve(1);
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::getQueue()->count(), 4);
self::assertEquals($onFulfilledCount, 0);
self::assertEquals($onRejectedCount, 0);
self::assertEquals(SyncPromise::PENDING, $nextPromise->state);
self::assertEquals(SyncPromise::PENDING, $nextPromise2->state);
self::assertEquals(SyncPromise::PENDING, $nextPromise3->state);
self::assertEquals(SyncPromise::PENDING, $nextPromise4->state);
SyncPromise::runQueue();
2018-09-19 18:12:09 +03:00
self::assertEquals(SyncPromise::getQueue()->count(), 0);
self::assertEquals($onFulfilledCount, 3);
self::assertEquals($onRejectedCount, 0);
self::assertValidPromise($nextPromise, null, 1, SyncPromise::FULFILLED);
self::assertValidPromise($nextPromise2, null, 1, SyncPromise::FULFILLED);
self::assertValidPromise($nextPromise3, null, 2, SyncPromise::FULFILLED);
self::assertValidPromise($nextPromise4, null, 3, SyncPromise::FULFILLED);
}
}