mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-25 06:16:05 +03:00
Merge branch 'master' into patch-1
This commit is contained in:
commit
e7513e356a
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
|||||||
|
.phpcs-cache
|
||||||
composer.phar
|
composer.phar
|
||||||
composer.lock
|
composer.lock
|
||||||
phpcs.xml
|
phpcs.xml
|
||||||
|
phpstan.neon
|
||||||
vendor/
|
vendor/
|
||||||
|
36
.travis.yml
36
.travis.yml
@ -6,10 +6,6 @@ php:
|
|||||||
- 7.2
|
- 7.2
|
||||||
- nightly
|
- nightly
|
||||||
|
|
||||||
matrix:
|
|
||||||
allow_failures:
|
|
||||||
- php: nightly
|
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $HOME/.composer/cache
|
- $HOME/.composer/cache
|
||||||
@ -18,10 +14,7 @@ before_install:
|
|||||||
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{,.disabled} || echo "xdebug not available"
|
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{,.disabled} || echo "xdebug not available"
|
||||||
- travis_retry composer self-update
|
- travis_retry composer self-update
|
||||||
|
|
||||||
install:
|
install: travis_retry composer update --prefer-dist
|
||||||
- composer require react/promise:2.*
|
|
||||||
- composer require psr/http-message:1.*
|
|
||||||
- travis_retry composer update --prefer-dist
|
|
||||||
|
|
||||||
script: ./vendor/bin/phpunit --group default,ReactPromise
|
script: ./vendor/bin/phpunit --group default,ReactPromise
|
||||||
|
|
||||||
@ -45,21 +38,16 @@ jobs:
|
|||||||
after_script:
|
after_script:
|
||||||
- wget https://scrutinizer-ci.com/ocular.phar
|
- wget https://scrutinizer-ci.com/ocular.phar
|
||||||
- php ocular.phar code-coverage:upload --format=php-clover clover.xml
|
- php ocular.phar code-coverage:upload --format=php-clover clover.xml
|
||||||
- stage: Pull request coding standard
|
|
||||||
if: type = pull_request
|
- stage: Code Quality
|
||||||
|
php: 7.1
|
||||||
|
env: CODING_STANDARD
|
||||||
install: travis_retry composer install --prefer-dist
|
install: travis_retry composer install --prefer-dist
|
||||||
script:
|
script:
|
||||||
- |
|
- ./vendor/bin/phpcs
|
||||||
if [ $TRAVIS_BRANCH != "master" ]; then
|
|
||||||
git remote set-branches --add origin $TRAVIS_BRANCH;
|
- stage: Code Quality
|
||||||
git fetch origin $TRAVIS_BRANCH;
|
php: 7.1
|
||||||
fi
|
env: STATIC_ANALYSIS
|
||||||
- git merge-base origin/$TRAVIS_BRANCH $TRAVIS_PULL_REQUEST_SHA || git fetch origin +refs/pull/$TRAVIS_PULL_REQUEST/merge --unshallow
|
install: travis_retry composer install --prefer-dist
|
||||||
- wget https://github.com/diff-sniffer/git/releases/download/0.1.0/git-phpcs.phar
|
script: composer static-analysis
|
||||||
- php git-phpcs.phar origin/$TRAVIS_BRANCH...$TRAVIS_PULL_REQUEST_SHA
|
|
||||||
# - stage: Coding standard
|
|
||||||
# if: NOT type = pull_request
|
|
||||||
# php: 7.1
|
|
||||||
# install: travis_retry composer install --prefer-dist
|
|
||||||
# script:
|
|
||||||
# - ./vendor/bin/phpcs
|
|
||||||
|
@ -25,6 +25,8 @@ composer install
|
|||||||
./vendor/bin/phpunit
|
./vendor/bin/phpunit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Some tests have annotation `@see it('<description>')`. It is used for reference to same tests in [graphql-js implementation](https://github.com/graphql/graphql-js) with the same description.
|
||||||
|
|
||||||
## Coding Standard
|
## Coding Standard
|
||||||
Coding standard of this project is based on [Doctrine CS](https://github.com/doctrine/coding-standard). To run the inspection:
|
Coding standard of this project is based on [Doctrine CS](https://github.com/doctrine/coding-standard). To run the inspection:
|
||||||
|
|
||||||
|
@ -15,8 +15,11 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"doctrine/coding-standard": "^4.0",
|
"doctrine/coding-standard": "^4.0",
|
||||||
|
"phpstan/phpstan": "^0.10.3",
|
||||||
|
"phpstan/phpstan-phpunit": "^0.10.0",
|
||||||
"phpunit/phpunit": "^7.2",
|
"phpunit/phpunit": "^7.2",
|
||||||
"psr/http-message": "^1.0"
|
"psr/http-message": "^1.0",
|
||||||
|
"react/promise": "2.*"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"preferred-install": "dist",
|
"preferred-install": "dist",
|
||||||
@ -39,6 +42,7 @@
|
|||||||
"psr/http-message": "To use standard GraphQL server"
|
"psr/http-message": "To use standard GraphQL server"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint" : "phpcs"
|
"lint" : "phpcs",
|
||||||
|
"static-analysis": "phpstan analyse --ansi -l 1 -c phpstan.neon.dist src tests"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ first learn about GraphQL on [the official website](http://graphql.org/learn/).
|
|||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
Using [composer](https://getcomposer.org/doc/00-intro.md), simply run:
|
Using [composer](https://getcomposer.org/doc/00-intro.md), run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
composer require webonyx/graphql-php
|
composer require webonyx/graphql-php
|
||||||
|
3
phpstan.neon.dist
Normal file
3
phpstan.neon.dist
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
includes:
|
||||||
|
- vendor/phpstan/phpstan-phpunit/extension.neon
|
||||||
|
- vendor/phpstan/phpstan-phpunit/rules.neon
|
@ -1,23 +1,20 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL;
|
namespace GraphQL;
|
||||||
|
|
||||||
use GraphQL\Executor\Promise\Adapter\SyncPromise;
|
use GraphQL\Executor\Promise\Adapter\SyncPromise;
|
||||||
|
|
||||||
class Deferred
|
class Deferred
|
||||||
{
|
{
|
||||||
/**
|
/** @var \SplQueue */
|
||||||
* @var \SplQueue
|
|
||||||
*/
|
|
||||||
private static $queue;
|
private static $queue;
|
||||||
|
|
||||||
/**
|
/** @var callable */
|
||||||
* @var callable
|
|
||||||
*/
|
|
||||||
private $callback;
|
private $callback;
|
||||||
|
|
||||||
/**
|
/** @var SyncPromise */
|
||||||
* @var SyncPromise
|
|
||||||
*/
|
|
||||||
public $promise;
|
public $promise;
|
||||||
|
|
||||||
public static function getQueue()
|
public static function getQueue()
|
||||||
@ -28,7 +25,7 @@ class Deferred
|
|||||||
public static function runQueue()
|
public static function runQueue()
|
||||||
{
|
{
|
||||||
$q = self::$queue;
|
$q = self::$queue;
|
||||||
while ($q && !$q->isEmpty()) {
|
while ($q && ! $q->isEmpty()) {
|
||||||
/** @var self $dfd */
|
/** @var self $dfd */
|
||||||
$dfd = $q->dequeue();
|
$dfd = $q->dequeue();
|
||||||
$dfd->run();
|
$dfd->run();
|
||||||
@ -47,7 +44,7 @@ class Deferred
|
|||||||
return $this->promise->then($onFulfilled, $onRejected);
|
return $this->promise->then($onFulfilled, $onRejected);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function run()
|
public function run() : void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$cb = $this->callback;
|
$cb = $this->callback;
|
||||||
|
@ -35,6 +35,7 @@ use GraphQL\Utils\TypeInfo;
|
|||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
use function array_keys;
|
use function array_keys;
|
||||||
use function array_merge;
|
use function array_merge;
|
||||||
|
use function array_reduce;
|
||||||
use function array_values;
|
use function array_values;
|
||||||
use function get_class;
|
use function get_class;
|
||||||
use function is_array;
|
use function is_array;
|
||||||
@ -996,7 +997,6 @@ class Executor
|
|||||||
* return a Promise.
|
* return a Promise.
|
||||||
*
|
*
|
||||||
* @param mixed[] $values
|
* @param mixed[] $values
|
||||||
* @param \Closure $callback
|
|
||||||
* @param Promise|mixed|null $initialValue
|
* @param Promise|mixed|null $initialValue
|
||||||
* @return mixed[]
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
@ -1291,23 +1291,18 @@ class Executor
|
|||||||
return $this->executeFields($returnType, $result, $path, $subFieldNodes);
|
return $this->executeFields($returnType, $result, $path, $subFieldNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function collectSubFields(ObjectType $returnType, $fieldNodes) : ArrayObject
|
||||||
* @param ObjectType $returnType
|
|
||||||
* @param $fieldNodes
|
|
||||||
* @return ArrayObject
|
|
||||||
*/
|
|
||||||
private function collectSubFields(ObjectType $returnType, $fieldNodes): ArrayObject
|
|
||||||
{
|
{
|
||||||
if (!isset($this->subFieldCache[$returnType])) {
|
if (! isset($this->subFieldCache[$returnType])) {
|
||||||
$this->subFieldCache[$returnType] = new \SplObjectStorage();
|
$this->subFieldCache[$returnType] = new \SplObjectStorage();
|
||||||
}
|
}
|
||||||
if (!isset($this->subFieldCache[$returnType][$fieldNodes])) {
|
if (! isset($this->subFieldCache[$returnType][$fieldNodes])) {
|
||||||
// Collect sub-fields to execute to complete this value.
|
// Collect sub-fields to execute to complete this value.
|
||||||
$subFieldNodes = new \ArrayObject();
|
$subFieldNodes = new \ArrayObject();
|
||||||
$visitedFragmentNames = new \ArrayObject();
|
$visitedFragmentNames = new \ArrayObject();
|
||||||
|
|
||||||
foreach ($fieldNodes as $fieldNode) {
|
foreach ($fieldNodes as $fieldNode) {
|
||||||
if (!isset($fieldNode->selectionSet)) {
|
if (! isset($fieldNode->selectionSet)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ namespace GraphQL\Executor\Promise;
|
|||||||
|
|
||||||
use GraphQL\Executor\Promise\Adapter\SyncPromise;
|
use GraphQL\Executor\Promise\Adapter\SyncPromise;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
|
use React\Promise\Promise as ReactPromise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience wrapper for promises represented by Promise Adapter
|
* Convenience wrapper for promises represented by Promise Adapter
|
||||||
|
142
src/GraphQL.php
142
src/GraphQL.php
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL;
|
namespace GraphQL;
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
@ -6,15 +9,19 @@ use GraphQL\Executor\ExecutionResult;
|
|||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
|
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
|
||||||
use GraphQL\Executor\Promise\Promise;
|
use GraphQL\Executor\Promise\Promise;
|
||||||
|
use GraphQL\Executor\Promise\PromiseAdapter;
|
||||||
use GraphQL\Language\AST\DocumentNode;
|
use GraphQL\Language\AST\DocumentNode;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\Source;
|
use GraphQL\Language\Source;
|
||||||
use GraphQL\Executor\Promise\PromiseAdapter;
|
|
||||||
use GraphQL\Type\Definition\Directive;
|
use GraphQL\Type\Definition\Directive;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema as SchemaType;
|
||||||
use GraphQL\Validator\DocumentValidator;
|
use GraphQL\Validator\DocumentValidator;
|
||||||
use GraphQL\Validator\Rules\ValidationRule;
|
|
||||||
use GraphQL\Validator\Rules\QueryComplexity;
|
use GraphQL\Validator\Rules\QueryComplexity;
|
||||||
|
use GraphQL\Validator\Rules\ValidationRule;
|
||||||
|
use function array_values;
|
||||||
|
use function trigger_error;
|
||||||
|
use const E_USER_DEPRECATED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the primary facade for fulfilling GraphQL operations.
|
* This is the primary facade for fulfilling GraphQL operations.
|
||||||
@ -58,32 +65,35 @@ class GraphQL
|
|||||||
* queries which are validated before persisting and assumed valid during execution)
|
* queries which are validated before persisting and assumed valid during execution)
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param \GraphQL\Type\Schema $schema
|
|
||||||
* @param string|DocumentNode $source
|
* @param string|DocumentNode $source
|
||||||
* @param mixed $rootValue
|
* @param mixed $rootValue
|
||||||
* @param mixed $context
|
* @param mixed $context
|
||||||
* @param array|null $variableValues
|
* @param mixed[]|null $variableValues
|
||||||
* @param string|null $operationName
|
* @param ValidationRule[] $validationRules
|
||||||
* @param callable $fieldResolver
|
|
||||||
* @param array $validationRules
|
|
||||||
*
|
|
||||||
* @return ExecutionResult
|
|
||||||
*/
|
*/
|
||||||
public static function executeQuery(
|
public static function executeQuery(
|
||||||
\GraphQL\Type\Schema $schema,
|
SchemaType $schema,
|
||||||
$source,
|
$source,
|
||||||
$rootValue = null,
|
$rootValue = null,
|
||||||
$context = null,
|
$context = null,
|
||||||
$variableValues = null,
|
$variableValues = null,
|
||||||
$operationName = null,
|
?string $operationName = null,
|
||||||
callable $fieldResolver = null,
|
?callable $fieldResolver = null,
|
||||||
array $validationRules = null
|
?array $validationRules = null
|
||||||
)
|
) : ExecutionResult {
|
||||||
{
|
|
||||||
$promiseAdapter = new SyncPromiseAdapter();
|
$promiseAdapter = new SyncPromiseAdapter();
|
||||||
|
|
||||||
$promise = self::promiseToExecute($promiseAdapter, $schema, $source, $rootValue, $context,
|
$promise = self::promiseToExecute(
|
||||||
$variableValues, $operationName, $fieldResolver, $validationRules);
|
$promiseAdapter,
|
||||||
|
$schema,
|
||||||
|
$source,
|
||||||
|
$rootValue,
|
||||||
|
$context,
|
||||||
|
$variableValues,
|
||||||
|
$operationName,
|
||||||
|
$fieldResolver,
|
||||||
|
$validationRules
|
||||||
|
);
|
||||||
|
|
||||||
return $promiseAdapter->wait($promise);
|
return $promiseAdapter->wait($promise);
|
||||||
}
|
}
|
||||||
@ -93,30 +103,23 @@ class GraphQL
|
|||||||
* Useful for Async PHP platforms.
|
* Useful for Async PHP platforms.
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param PromiseAdapter $promiseAdapter
|
|
||||||
* @param \GraphQL\Type\Schema $schema
|
|
||||||
* @param string|DocumentNode $source
|
* @param string|DocumentNode $source
|
||||||
* @param mixed $rootValue
|
* @param mixed $rootValue
|
||||||
* @param mixed $context
|
* @param mixed $context
|
||||||
* @param array|null $variableValues
|
* @param mixed[]|null $variableValues
|
||||||
* @param string|null $operationName
|
* @param ValidationRule[]|null $validationRules
|
||||||
* @param callable $fieldResolver
|
|
||||||
* @param array $validationRules
|
|
||||||
*
|
|
||||||
* @return Promise
|
|
||||||
*/
|
*/
|
||||||
public static function promiseToExecute(
|
public static function promiseToExecute(
|
||||||
PromiseAdapter $promiseAdapter,
|
PromiseAdapter $promiseAdapter,
|
||||||
\GraphQL\Type\Schema $schema,
|
SchemaType $schema,
|
||||||
$source,
|
$source,
|
||||||
$rootValue = null,
|
$rootValue = null,
|
||||||
$context = null,
|
$context = null,
|
||||||
$variableValues = null,
|
$variableValues = null,
|
||||||
$operationName = null,
|
?string $operationName = null,
|
||||||
callable $fieldResolver = null,
|
?callable $fieldResolver = null,
|
||||||
array $validationRules = null
|
?array $validationRules = null
|
||||||
)
|
) : Promise {
|
||||||
{
|
|
||||||
try {
|
try {
|
||||||
if ($source instanceof DocumentNode) {
|
if ($source instanceof DocumentNode) {
|
||||||
$documentNode = $source;
|
$documentNode = $source;
|
||||||
@ -125,25 +128,28 @@ class GraphQL
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME
|
// FIXME
|
||||||
if (!empty($validationRules)) {
|
if (empty($validationRules)) {
|
||||||
foreach ($validationRules as $rule) {
|
|
||||||
if ($rule instanceof QueryComplexity) {
|
|
||||||
$rule->setRawVariableValues($variableValues);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/** @var QueryComplexity $queryComplexity */
|
/** @var QueryComplexity $queryComplexity */
|
||||||
$queryComplexity = DocumentValidator::getRule(QueryComplexity::class);
|
$queryComplexity = DocumentValidator::getRule(QueryComplexity::class);
|
||||||
$queryComplexity->setRawVariableValues($variableValues);
|
$queryComplexity->setRawVariableValues($variableValues);
|
||||||
|
} else {
|
||||||
|
foreach ($validationRules as $rule) {
|
||||||
|
if (! ($rule instanceof QueryComplexity)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rule->setRawVariableValues($variableValues);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$validationErrors = DocumentValidator::validate($schema, $documentNode, $validationRules);
|
$validationErrors = DocumentValidator::validate($schema, $documentNode, $validationRules);
|
||||||
|
|
||||||
if (!empty($validationErrors)) {
|
if (! empty($validationErrors)) {
|
||||||
return $promiseAdapter->createFulfilled(
|
return $promiseAdapter->createFulfilled(
|
||||||
new ExecutionResult(null, $validationErrors)
|
new ExecutionResult(null, $validationErrors)
|
||||||
);
|
);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return Executor::promiseToExecute(
|
return Executor::promiseToExecute(
|
||||||
$promiseAdapter,
|
$promiseAdapter,
|
||||||
$schema,
|
$schema,
|
||||||
@ -154,7 +160,6 @@ class GraphQL
|
|||||||
$operationName,
|
$operationName,
|
||||||
$fieldResolver
|
$fieldResolver
|
||||||
);
|
);
|
||||||
}
|
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
return $promiseAdapter->createFulfilled(
|
return $promiseAdapter->createFulfilled(
|
||||||
new ExecutionResult(null, [$e])
|
new ExecutionResult(null, [$e])
|
||||||
@ -165,29 +170,28 @@ class GraphQL
|
|||||||
/**
|
/**
|
||||||
* @deprecated Use executeQuery()->toArray() instead
|
* @deprecated Use executeQuery()->toArray() instead
|
||||||
*
|
*
|
||||||
* @param \GraphQL\Type\Schema $schema
|
|
||||||
* @param string|DocumentNode $source
|
* @param string|DocumentNode $source
|
||||||
* @param mixed $rootValue
|
* @param mixed $rootValue
|
||||||
* @param mixed $contextValue
|
* @param mixed $contextValue
|
||||||
* @param array|null $variableValues
|
* @param mixed[]|null $variableValues
|
||||||
* @param string|null $operationName
|
* @return Promise|mixed[]
|
||||||
* @return Promise|array
|
|
||||||
*/
|
*/
|
||||||
public static function execute(
|
public static function execute(
|
||||||
\GraphQL\Type\Schema $schema,
|
SchemaType $schema,
|
||||||
$source,
|
$source,
|
||||||
$rootValue = null,
|
$rootValue = null,
|
||||||
$contextValue = null,
|
$contextValue = null,
|
||||||
$variableValues = null,
|
$variableValues = null,
|
||||||
$operationName = null
|
?string $operationName = null
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
trigger_error(
|
trigger_error(
|
||||||
__METHOD__ . ' is deprecated, use GraphQL::executeQuery()->toArray() as a quick replacement',
|
__METHOD__ . ' is deprecated, use GraphQL::executeQuery()->toArray() as a quick replacement',
|
||||||
E_USER_DEPRECATED
|
E_USER_DEPRECATED
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$promiseAdapter = Executor::getPromiseAdapter();
|
||||||
$result = self::promiseToExecute(
|
$result = self::promiseToExecute(
|
||||||
$promiseAdapter = Executor::getPromiseAdapter(),
|
$promiseAdapter,
|
||||||
$schema,
|
$schema,
|
||||||
$source,
|
$source,
|
||||||
$rootValue,
|
$rootValue,
|
||||||
@ -199,40 +203,40 @@ class GraphQL
|
|||||||
if ($promiseAdapter instanceof SyncPromiseAdapter) {
|
if ($promiseAdapter instanceof SyncPromiseAdapter) {
|
||||||
$result = $promiseAdapter->wait($result)->toArray();
|
$result = $promiseAdapter->wait($result)->toArray();
|
||||||
} else {
|
} else {
|
||||||
$result = $result->then(function(ExecutionResult $r) {
|
$result = $result->then(function (ExecutionResult $r) {
|
||||||
return $r->toArray();
|
return $r->toArray();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated renamed to executeQuery()
|
* @deprecated renamed to executeQuery()
|
||||||
*
|
*
|
||||||
* @param \GraphQL\Type\Schema $schema
|
|
||||||
* @param string|DocumentNode $source
|
* @param string|DocumentNode $source
|
||||||
* @param mixed $rootValue
|
* @param mixed $rootValue
|
||||||
* @param mixed $contextValue
|
* @param mixed $contextValue
|
||||||
* @param array|null $variableValues
|
* @param mixed[]|null $variableValues
|
||||||
* @param string|null $operationName
|
|
||||||
*
|
*
|
||||||
* @return ExecutionResult|Promise
|
* @return ExecutionResult|Promise
|
||||||
*/
|
*/
|
||||||
public static function executeAndReturnResult(
|
public static function executeAndReturnResult(
|
||||||
\GraphQL\Type\Schema $schema,
|
SchemaType $schema,
|
||||||
$source,
|
$source,
|
||||||
$rootValue = null,
|
$rootValue = null,
|
||||||
$contextValue = null,
|
$contextValue = null,
|
||||||
$variableValues = null,
|
$variableValues = null,
|
||||||
$operationName = null
|
?string $operationName = null
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
trigger_error(
|
trigger_error(
|
||||||
__METHOD__ . ' is deprecated, use GraphQL::executeQuery() as a quick replacement',
|
__METHOD__ . ' is deprecated, use GraphQL::executeQuery() as a quick replacement',
|
||||||
E_USER_DEPRECATED
|
E_USER_DEPRECATED
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$promiseAdapter = Executor::getPromiseAdapter();
|
||||||
$result = self::promiseToExecute(
|
$result = self::promiseToExecute(
|
||||||
$promiseAdapter = Executor::getPromiseAdapter(),
|
$promiseAdapter,
|
||||||
$schema,
|
$schema,
|
||||||
$source,
|
$source,
|
||||||
$rootValue,
|
$rootValue,
|
||||||
@ -240,9 +244,11 @@ class GraphQL
|
|||||||
$variableValues,
|
$variableValues,
|
||||||
$operationName
|
$operationName
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($promiseAdapter instanceof SyncPromiseAdapter) {
|
if ($promiseAdapter instanceof SyncPromiseAdapter) {
|
||||||
$result = $promiseAdapter->wait($result);
|
$result = $promiseAdapter->wait($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +258,7 @@ class GraphQL
|
|||||||
* @api
|
* @api
|
||||||
* @return Directive[]
|
* @return Directive[]
|
||||||
*/
|
*/
|
||||||
public static function getStandardDirectives()
|
public static function getStandardDirectives() : array
|
||||||
{
|
{
|
||||||
return array_values(Directive::getInternalDirectives());
|
return array_values(Directive::getInternalDirectives());
|
||||||
}
|
}
|
||||||
@ -263,7 +269,7 @@ class GraphQL
|
|||||||
* @api
|
* @api
|
||||||
* @return Type[]
|
* @return Type[]
|
||||||
*/
|
*/
|
||||||
public static function getStandardTypes()
|
public static function getStandardTypes() : array
|
||||||
{
|
{
|
||||||
return array_values(Type::getInternalTypes());
|
return array_values(Type::getInternalTypes());
|
||||||
}
|
}
|
||||||
@ -274,23 +280,17 @@ class GraphQL
|
|||||||
* @api
|
* @api
|
||||||
* @return ValidationRule[]
|
* @return ValidationRule[]
|
||||||
*/
|
*/
|
||||||
public static function getStandardValidationRules()
|
public static function getStandardValidationRules() : array
|
||||||
{
|
{
|
||||||
return array_values(DocumentValidator::defaultRules());
|
return array_values(DocumentValidator::defaultRules());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static function setDefaultFieldResolver(callable $fn) : void
|
||||||
* @param callable $fn
|
|
||||||
*/
|
|
||||||
public static function setDefaultFieldResolver(callable $fn)
|
|
||||||
{
|
{
|
||||||
Executor::setDefaultFieldResolver($fn);
|
Executor::setDefaultFieldResolver($fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static function setPromiseAdapter(?PromiseAdapter $promiseAdapter = null) : void
|
||||||
* @param PromiseAdapter|null $promiseAdapter
|
|
||||||
*/
|
|
||||||
public static function setPromiseAdapter(PromiseAdapter $promiseAdapter = null)
|
|
||||||
{
|
{
|
||||||
Executor::setPromiseAdapter($promiseAdapter);
|
Executor::setPromiseAdapter($promiseAdapter);
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ class GraphQL
|
|||||||
* @deprecated Renamed to getStandardDirectives
|
* @deprecated Renamed to getStandardDirectives
|
||||||
* @return Directive[]
|
* @return Directive[]
|
||||||
*/
|
*/
|
||||||
public static function getInternalDirectives()
|
public static function getInternalDirectives() : array
|
||||||
{
|
{
|
||||||
return self::getStandardDirectives();
|
return self::getStandardDirectives();
|
||||||
}
|
}
|
||||||
|
@ -264,6 +264,7 @@ class Visitor
|
|||||||
|
|
||||||
if ($visitFn) {
|
if ($visitFn) {
|
||||||
$result = call_user_func($visitFn, $node, $key, $parent, $path, $ancestors);
|
$result = call_user_func($visitFn, $node, $key, $parent, $path, $ancestors);
|
||||||
|
$editValue = null;
|
||||||
|
|
||||||
if ($result !== null) {
|
if ($result !== null) {
|
||||||
if ($result instanceof VisitorOperation) {
|
if ($result instanceof VisitorOperation) {
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL;
|
namespace GraphQL;
|
||||||
|
|
||||||
|
use function trigger_error;
|
||||||
|
use const E_USER_DEPRECATED;
|
||||||
|
|
||||||
trigger_error(
|
trigger_error(
|
||||||
'GraphQL\Schema is moved to GraphQL\Type\Schema',
|
'GraphQL\Schema is moved to GraphQL\Type\Schema',
|
||||||
E_USER_DEPRECATED
|
E_USER_DEPRECATED
|
||||||
|
@ -4,11 +4,11 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace GraphQL\Server;
|
namespace GraphQL\Server;
|
||||||
|
|
||||||
use const CASE_LOWER;
|
|
||||||
use function array_change_key_case;
|
use function array_change_key_case;
|
||||||
use function is_string;
|
use function is_string;
|
||||||
use function json_decode;
|
use function json_decode;
|
||||||
use function json_last_error;
|
use function json_last_error;
|
||||||
|
use const CASE_LOWER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structure representing parsed HTTP parameters for GraphQL operation
|
* Structure representing parsed HTTP parameters for GraphQL operation
|
||||||
|
@ -8,7 +8,7 @@ use GraphQL\Error\FormattedError;
|
|||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
use GraphQL\Executor\Promise\Promise;
|
use GraphQL\Executor\Promise\Promise;
|
||||||
use GraphQL\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Psr\Http\Message\StreamInterface;
|
use Psr\Http\Message\StreamInterface;
|
||||||
|
@ -21,7 +21,7 @@ class InputObjectField
|
|||||||
/** @var string|null */
|
/** @var string|null */
|
||||||
public $description;
|
public $description;
|
||||||
|
|
||||||
/** @var callback|InputType */
|
/** @var callable|InputType */
|
||||||
public $type;
|
public $type;
|
||||||
|
|
||||||
/** @var InputValueDefinitionNode|null */
|
/** @var InputValueDefinitionNode|null */
|
||||||
|
@ -12,7 +12,6 @@ use function is_array;
|
|||||||
use function is_callable;
|
use function is_callable;
|
||||||
use function is_string;
|
use function is_string;
|
||||||
use function sprintf;
|
use function sprintf;
|
||||||
use function spritnf;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class InputObjectType
|
* Class InputObjectType
|
||||||
@ -70,7 +69,7 @@ class InputObjectType extends Type implements InputType, NamedType
|
|||||||
|
|
||||||
if (! is_array($fields)) {
|
if (! is_array($fields)) {
|
||||||
throw new InvariantViolation(
|
throw new InvariantViolation(
|
||||||
spritnf('%s fields must be an array or a callable which returns such an array.', $this->name)
|
sprintf('%s fields must be an array or a callable which returns such an array.', $this->name)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ values. Int can represent values between -(2^31) and 2^31 - 1. ';
|
|||||||
}
|
}
|
||||||
$int = intval($num);
|
$int = intval($num);
|
||||||
// int cast with == used for performance reasons
|
// int cast with == used for performance reasons
|
||||||
// @codingStandardsIgnoreLine
|
// phpcs:ignore
|
||||||
if ($int != $num) {
|
if ($int != $num) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Int cannot represent non-integer value: ' .
|
'Int cannot represent non-integer value: ' .
|
||||||
|
@ -255,7 +255,7 @@ class AST
|
|||||||
}
|
}
|
||||||
if (is_float($serialized)) {
|
if (is_float($serialized)) {
|
||||||
// int cast with == used for performance reasons
|
// int cast with == used for performance reasons
|
||||||
// @codingStandardsIgnoreLine
|
// phpcs:ignore
|
||||||
if ((int) $serialized == $serialized) {
|
if ((int) $serialized == $serialized) {
|
||||||
return new IntValueNode(['value' => $serialized]);
|
return new IntValueNode(['value' => $serialized]);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,9 @@ namespace GraphQL\Validator\Rules;
|
|||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
use GraphQL\Language\AST\DirectiveNode;
|
use GraphQL\Language\AST\DirectiveNode;
|
||||||
use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
|
use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
|
||||||
|
use GraphQL\Language\AST\Node;
|
||||||
use GraphQL\Language\AST\NodeKind;
|
use GraphQL\Language\AST\NodeKind;
|
||||||
|
use GraphQL\Language\AST\NodeList;
|
||||||
use GraphQL\Language\DirectiveLocation;
|
use GraphQL\Language\DirectiveLocation;
|
||||||
use GraphQL\Validator\ValidationContext;
|
use GraphQL\Validator\ValidationContext;
|
||||||
use function count;
|
use function count;
|
||||||
@ -59,7 +61,9 @@ class KnownDirectives extends ValidationRule
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param (Node|NodeList)[] $ancestors
|
* @param Node[]|NodeList[] $ancestors The type is actually (Node|NodeList)[] but this PSR-5 syntax is so far not supported by most of the tools
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function getDirectiveLocationForASTPath(array $ancestors)
|
private function getDirectiveLocationForASTPath(array $ancestors)
|
||||||
{
|
{
|
||||||
|
@ -44,10 +44,10 @@ class VariablesDefaultValueAllowed extends ValidationRule
|
|||||||
|
|
||||||
return Visitor::skipNode();
|
return Visitor::skipNode();
|
||||||
},
|
},
|
||||||
NodeKind::SELECTION_SET => function (SelectionSetNode $node) use ($context) {
|
NodeKind::SELECTION_SET => function (SelectionSetNode $node) {
|
||||||
return Visitor::skipNode();
|
return Visitor::skipNode();
|
||||||
},
|
},
|
||||||
NodeKind::FRAGMENT_DEFINITION => function (FragmentDefinitionNode $node) use ($context) {
|
NodeKind::FRAGMENT_DEFINITION => function (FragmentDefinitionNode $node) {
|
||||||
return Visitor::skipNode();
|
return Visitor::skipNode();
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -1,23 +1,27 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
use GraphQL\Error\UserError;
|
use GraphQL\Error\UserError;
|
||||||
use GraphQL\Error\Warning;
|
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Tests\Executor\TestClasses\Cat;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Dog;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Human;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\UnionType;
|
use GraphQL\Type\Definition\UnionType;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DESCRIBE: Execute: Handles execution of abstract types with promises
|
||||||
|
*/
|
||||||
class AbstractPromiseTest extends TestCase
|
class AbstractPromiseTest extends TestCase
|
||||||
{
|
{
|
||||||
// DESCRIBE: Execute: Handles execution of abstract types with promises
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('isTypeOf used to resolve runtime type for Interface')
|
* @see it('isTypeOf used to resolve runtime type for Interface')
|
||||||
*/
|
*/
|
||||||
@ -26,36 +30,36 @@ class AbstractPromiseTest extends TestCase
|
|||||||
$PetType = new InterfaceType([
|
$PetType = new InterfaceType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => [ 'type' => Type::string() ]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'interfaces' => [ $PetType ],
|
'interfaces' => [$PetType],
|
||||||
'isTypeOf' => function($obj) {
|
'isTypeOf' => function ($obj) {
|
||||||
return new Deferred(function() use ($obj) {
|
return new Deferred(function () use ($obj) {
|
||||||
return $obj instanceof Dog;
|
return $obj instanceof Dog;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => [ 'type' => Type::string() ],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => [ 'type' => Type::boolean() ],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
'name' => 'Cat',
|
'name' => 'Cat',
|
||||||
'interfaces' => [ $PetType ],
|
'interfaces' => [$PetType],
|
||||||
'isTypeOf' => function($obj) {
|
'isTypeOf' => function ($obj) {
|
||||||
return new Deferred(function() use ($obj) {
|
return new Deferred(function () use ($obj) {
|
||||||
return $obj instanceof Cat;
|
return $obj instanceof Cat;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => [ 'type' => Type::string() ],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => [ 'type' => Type::boolean() ],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -64,16 +68,16 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'pets' => [
|
'pets' => [
|
||||||
'type' => Type::listOf($PetType),
|
'type' => Type::listOf($PetType),
|
||||||
'resolve' => function() {
|
'resolve' => function () {
|
||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false)
|
new Cat('Garfield', false),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [ $CatType, $DogType ]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -93,10 +97,10 @@ class AbstractPromiseTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [
|
'pets' => [
|
||||||
[ 'name' => 'Odie', 'woofs' => true ],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
[ 'name' => 'Garfield', 'meows' => false ]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
@ -107,12 +111,11 @@ class AbstractPromiseTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testIsTypeOfCanBeRejected() : void
|
public function testIsTypeOfCanBeRejected() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$PetType = new InterfaceType([
|
$PetType = new InterfaceType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -126,7 +129,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -140,7 +143,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -152,13 +155,13 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false)
|
new Cat('Garfield', false),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$CatType, $DogType]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -177,7 +180,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [null, null]
|
'pets' => [null, null],
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
@ -188,9 +191,9 @@ class AbstractPromiseTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'We are testing this error',
|
'message' => 'We are testing this error',
|
||||||
'locations' => [['line' => 2, 'column' => 7]],
|
'locations' => [['line' => 2, 'column' => 7]],
|
||||||
'path' => ['pets', 1]
|
'path' => ['pets', 1],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result);
|
$this->assertArraySubset($expected, $result);
|
||||||
@ -201,7 +204,6 @@ class AbstractPromiseTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testIsTypeOfUsedToResolveRuntimeTypeForUnion() : void
|
public function testIsTypeOfUsedToResolveRuntimeTypeForUnion() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'isTypeOf' => function ($obj) {
|
'isTypeOf' => function ($obj) {
|
||||||
@ -212,7 +214,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -225,12 +227,12 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PetType = new UnionType([
|
$PetType = new UnionType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'types' => [$DogType, $CatType]
|
'types' => [$DogType, $CatType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -241,10 +243,10 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'type' => Type::listOf($PetType),
|
'type' => Type::listOf($PetType),
|
||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -266,9 +268,9 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
@ -292,19 +294,20 @@ class AbstractPromiseTest extends TestCase
|
|||||||
if ($obj instanceof Human) {
|
if ($obj instanceof Human) {
|
||||||
return $HumanType;
|
return $HumanType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$HumanType = new ObjectType([
|
$HumanType = new ObjectType([
|
||||||
'name' => 'Human',
|
'name' => 'Human',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -313,7 +316,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -322,7 +325,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -336,14 +339,14 @@ class AbstractPromiseTest extends TestCase
|
|||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false),
|
new Cat('Garfield', false),
|
||||||
new Human('Jon')
|
new Human('Jon'),
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$CatType, $DogType]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -365,16 +368,16 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false],
|
['name' => 'Garfield', 'meows' => false],
|
||||||
null
|
null,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
||||||
'locations' => [['line' => 2, 'column' => 7]],
|
'locations' => [['line' => 2, 'column' => 7]],
|
||||||
'path' => ['pets', 2]
|
'path' => ['pets', 2],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result);
|
$this->assertArraySubset($expected, $result);
|
||||||
@ -385,12 +388,11 @@ class AbstractPromiseTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testResolveTypeOnUnionYieldsUsefulError() : void
|
public function testResolveTypeOnUnionYieldsUsefulError() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$HumanType = new ObjectType([
|
$HumanType = new ObjectType([
|
||||||
'name' => 'Human',
|
'name' => 'Human',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -398,7 +400,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -406,7 +408,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PetType = new UnionType([
|
$PetType = new UnionType([
|
||||||
@ -422,10 +424,11 @@ class AbstractPromiseTest extends TestCase
|
|||||||
if ($obj instanceof Human) {
|
if ($obj instanceof Human) {
|
||||||
return $HumanType;
|
return $HumanType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
'types' => [$DogType, $CatType]
|
'types' => [$DogType, $CatType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -438,12 +441,12 @@ class AbstractPromiseTest extends TestCase
|
|||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false),
|
new Cat('Garfield', false),
|
||||||
new Human('Jon')
|
new Human('Jon'),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -466,16 +469,16 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false],
|
['name' => 'Garfield', 'meows' => false],
|
||||||
null
|
null,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
||||||
'locations' => [['line' => 2, 'column' => 7]],
|
'locations' => [['line' => 2, 'column' => 7]],
|
||||||
'path' => ['pets', 2]
|
'path' => ['pets', 2],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result);
|
$this->assertArraySubset($expected, $result);
|
||||||
@ -496,22 +499,22 @@ class AbstractPromiseTest extends TestCase
|
|||||||
if ($obj instanceof Cat) {
|
if ($obj instanceof Cat) {
|
||||||
return 'Cat';
|
return 'Cat';
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'interfaces' => [$PetType],
|
'interfaces' => [$PetType],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -520,7 +523,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -532,13 +535,13 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false)
|
new Cat('Garfield', false),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$CatType, $DogType]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -560,8 +563,8 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false],
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
}
|
}
|
||||||
@ -571,7 +574,6 @@ class AbstractPromiseTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testResolveTypeCanBeCaught() : void
|
public function testResolveTypeCanBeCaught() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$PetType = new InterfaceType([
|
$PetType = new InterfaceType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'resolveType' => function () {
|
'resolveType' => function () {
|
||||||
@ -580,8 +582,8 @@ class AbstractPromiseTest extends TestCase
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -590,7 +592,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -599,7 +601,7 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -611,13 +613,13 @@ class AbstractPromiseTest extends TestCase
|
|||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false)
|
new Cat('Garfield', false),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$CatType, $DogType]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -636,20 +638,20 @@ class AbstractPromiseTest extends TestCase
|
|||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [null, null]
|
'pets' => [null, null],
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' => 'We are testing this error',
|
'message' => 'We are testing this error',
|
||||||
'locations' => [['line' => 2, 'column' => 7]],
|
'locations' => [['line' => 2, 'column' => 7]],
|
||||||
'path' => ['pets', 0]
|
'path' => ['pets', 0],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'message' => 'We are testing this error',
|
'message' => 'We are testing this error',
|
||||||
'locations' => [['line' => 2, 'column' => 7]],
|
'locations' => [['line' => 2, 'column' => 7]],
|
||||||
'path' => ['pets', 1]
|
'path' => ['pets', 1],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result);
|
$this->assertArraySubset($expected, $result);
|
||||||
|
@ -1,23 +1,28 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Executor;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Tests\Executor\TestClasses\Cat;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Dog;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Human;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\UnionType;
|
use GraphQL\Type\Definition\UnionType;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute: Handles execution of abstract types
|
||||||
|
*/
|
||||||
class AbstractTest extends TestCase
|
class AbstractTest extends TestCase
|
||||||
{
|
{
|
||||||
// Execute: Handles execution of abstract types
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('isTypeOf used to resolve runtime type for Interface')
|
* @see it('isTypeOf used to resolve runtime type for Interface')
|
||||||
*/
|
*/
|
||||||
@ -27,19 +32,21 @@ class AbstractTest extends TestCase
|
|||||||
$petType = new InterfaceType([
|
$petType = new InterfaceType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Added to interface type when defined
|
// Added to interface type when defined
|
||||||
$dogType = new ObjectType([
|
$dogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'interfaces' => [$petType],
|
'interfaces' => [$petType],
|
||||||
'isTypeOf' => function($obj) { return $obj instanceof Dog; },
|
'isTypeOf' => function ($obj) {
|
||||||
|
return $obj instanceof Dog;
|
||||||
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()]
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$catType = new ObjectType([
|
$catType = new ObjectType([
|
||||||
@ -51,7 +58,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -62,11 +69,11 @@ class AbstractTest extends TestCase
|
|||||||
'type' => Type::listOf($petType),
|
'type' => Type::listOf($petType),
|
||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$catType, $dogType]
|
'types' => [$catType, $dogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -84,8 +91,8 @@ class AbstractTest extends TestCase
|
|||||||
$expected = new ExecutionResult([
|
$expected = new ExecutionResult([
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$result = Executor::execute($schema, Parser::parse($query));
|
$result = Executor::execute($schema, Parser::parse($query));
|
||||||
@ -99,11 +106,13 @@ class AbstractTest extends TestCase
|
|||||||
{
|
{
|
||||||
$dogType = new ObjectType([
|
$dogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'isTypeOf' => function($obj) { return $obj instanceof Dog; },
|
'isTypeOf' => function ($obj) {
|
||||||
|
return $obj instanceof Dog;
|
||||||
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()]
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$catType = new ObjectType([
|
$catType = new ObjectType([
|
||||||
@ -114,12 +123,12 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$petType = new UnionType([
|
$petType = new UnionType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'types' => [$dogType, $catType]
|
'types' => [$dogType, $catType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -128,12 +137,12 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'pets' => [
|
'pets' => [
|
||||||
'type' => Type::listOf($petType),
|
'type' => Type::listOf($petType),
|
||||||
'resolve' => function() {
|
'resolve' => function () {
|
||||||
return [ new Dog('Odie', true), new Cat('Garfield', false) ];
|
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -151,8 +160,8 @@ class AbstractTest extends TestCase
|
|||||||
$expected = new ExecutionResult([
|
$expected = new ExecutionResult([
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($schema, Parser::parse($query)));
|
$this->assertEquals($expected, Executor::execute($schema, Parser::parse($query)));
|
||||||
@ -161,7 +170,7 @@ class AbstractTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @see it('resolveType on Interface yields useful error')
|
* @see it('resolveType on Interface yields useful error')
|
||||||
*/
|
*/
|
||||||
function testResolveTypeOnInterfaceYieldsUsefulError()
|
public function testResolveTypeOnInterfaceYieldsUsefulError() : void
|
||||||
{
|
{
|
||||||
$DogType = null;
|
$DogType = null;
|
||||||
$CatType = null;
|
$CatType = null;
|
||||||
@ -179,18 +188,19 @@ class AbstractTest extends TestCase
|
|||||||
if ($obj instanceof Human) {
|
if ($obj instanceof Human) {
|
||||||
return $HumanType;
|
return $HumanType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$HumanType = new ObjectType([
|
$HumanType = new ObjectType([
|
||||||
'name' => 'Human',
|
'name' => 'Human',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -199,7 +209,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -208,7 +218,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -221,16 +231,15 @@ class AbstractTest extends TestCase
|
|||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false),
|
new Cat('Garfield', false),
|
||||||
new Human('Jon')
|
new Human('Jon'),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$DogType, $CatType]
|
'types' => [$DogType, $CatType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
pets {
|
pets {
|
||||||
name
|
name
|
||||||
@ -248,14 +257,15 @@ class AbstractTest extends TestCase
|
|||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false],
|
['name' => 'Garfield', 'meows' => false],
|
||||||
null
|
null,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'errors' => [[
|
'errors' => [[
|
||||||
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
||||||
'locations' => [['line' => 2, 'column' => 11]],
|
'locations' => [['line' => 2, 'column' => 11]],
|
||||||
'path' => ['pets', 2]
|
'path' => ['pets', 2],
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$actual = GraphQL::executeQuery($schema, $query)->toArray(true);
|
$actual = GraphQL::executeQuery($schema, $query)->toArray(true);
|
||||||
|
|
||||||
@ -271,7 +281,7 @@ class AbstractTest extends TestCase
|
|||||||
'name' => 'Human',
|
'name' => 'Human',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -279,7 +289,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -287,7 +297,7 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PetType = new UnionType([
|
$PetType = new UnionType([
|
||||||
@ -303,7 +313,7 @@ class AbstractTest extends TestCase
|
|||||||
return $HumanType;
|
return $HumanType;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'types' => [$DogType, $CatType]
|
'types' => [$DogType, $CatType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -316,12 +326,12 @@ class AbstractTest extends TestCase
|
|||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false),
|
new Cat('Garfield', false),
|
||||||
new Human('Jon')
|
new Human('Jon'),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -341,18 +351,23 @@ class AbstractTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie',
|
[
|
||||||
'woofs' => true],
|
'name' => 'Odie',
|
||||||
['name' => 'Garfield',
|
'woofs' => true,
|
||||||
'meows' => false],
|
],
|
||||||
null
|
[
|
||||||
]
|
'name' => 'Garfield',
|
||||||
|
'meows' => false,
|
||||||
|
],
|
||||||
|
null,
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'errors' => [[
|
'errors' => [[
|
||||||
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
'debugMessage' => 'Runtime Object type "Human" is not a possible type for "Pet".',
|
||||||
'locations' => [['line' => 2, 'column' => 11]],
|
'locations' => [['line' => 2, 'column' => 11]],
|
||||||
'path' => ['pets', 2]
|
'path' => ['pets', 2],
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, $result);
|
$this->assertArraySubset($expected, $result);
|
||||||
}
|
}
|
||||||
@ -419,32 +434,37 @@ class AbstractTest extends TestCase
|
|||||||
{
|
{
|
||||||
$PetType = new InterfaceType([
|
$PetType = new InterfaceType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'resolveType' => function($obj) {
|
'resolveType' => function ($obj) {
|
||||||
if ($obj instanceof Dog) return 'Dog';
|
if ($obj instanceof Dog) {
|
||||||
if ($obj instanceof Cat) return 'Cat';
|
return 'Dog';
|
||||||
|
}
|
||||||
|
if ($obj instanceof Cat) {
|
||||||
|
return 'Cat';
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => [ 'type' => Type::string() ]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'interfaces' => [ $PetType ],
|
'interfaces' => [$PetType],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => [ 'type' => Type::string() ],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => [ 'type' => Type::boolean() ],
|
'woofs' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
'name' => 'Cat',
|
'name' => 'Cat',
|
||||||
'interfaces' => [ $PetType ],
|
'interfaces' => [$PetType],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => [ 'type' => Type::string() ],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => [ 'type' => Type::boolean() ],
|
'meows' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -453,16 +473,16 @@ class AbstractTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'pets' => [
|
'pets' => [
|
||||||
'type' => Type::listOf($PetType),
|
'type' => Type::listOf($PetType),
|
||||||
'resolve' => function() {
|
'resolve' => function () {
|
||||||
return [
|
return [
|
||||||
new Dog('Odie', true),
|
new Dog('Odie', true),
|
||||||
new Cat('Garfield', false)
|
new Cat('Garfield', false),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [ $CatType, $DogType ]
|
'types' => [$CatType, $DogType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -479,51 +499,52 @@ class AbstractTest extends TestCase
|
|||||||
|
|
||||||
$result = GraphQL::executeQuery($schema, $query)->toArray();
|
$result = GraphQL::executeQuery($schema, $query)->toArray();
|
||||||
|
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'data' => [
|
'data' => [
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
], $result);
|
],
|
||||||
|
$result
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHintsOnConflictingTypeInstancesInResolveType() : void
|
public function testHintsOnConflictingTypeInstancesInResolveType() : void
|
||||||
{
|
{
|
||||||
$createTest = function() use (&$iface) {
|
$createTest = function () use (&$iface) {
|
||||||
return new ObjectType([
|
return new ObjectType([
|
||||||
'name' => 'Test',
|
'name' => 'Test',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => Type::string()
|
'a' => Type::string(),
|
||||||
],
|
],
|
||||||
'interfaces' => function() use ($iface) {
|
'interfaces' => function () use ($iface) {
|
||||||
return [$iface];
|
return [$iface];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
$iface = new InterfaceType([
|
$iface = new InterfaceType([
|
||||||
'name' => 'Node',
|
'name' => 'Node',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'a' => Type::string()
|
'a' => Type::string(),
|
||||||
],
|
],
|
||||||
'resolveType' => function() use (&$createTest) {
|
'resolveType' => function () use (&$createTest) {
|
||||||
return $createTest();
|
return $createTest();
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'node' => $iface,
|
'node' => $iface,
|
||||||
'test' => $createTest()
|
'test' => $createTest(),
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema(['query' => $query]);
|
||||||
'query' => $query,
|
|
||||||
]);
|
|
||||||
$schema->assertValid();
|
$schema->assertValid();
|
||||||
|
|
||||||
$query = '
|
$query = '
|
||||||
@ -537,9 +558,9 @@ class AbstractTest extends TestCase
|
|||||||
$result = Executor::execute($schema, Parser::parse($query), ['node' => ['a' => 'value']]);
|
$result = Executor::execute($schema, Parser::parse($query), ['node' => ['a' => 'value']]);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'Schema must contain unique named types but contains multiple types named "Test". '.
|
'Schema must contain unique named types but contains multiple types named "Test". ' .
|
||||||
'Make sure that `resolveType` function of abstract type "Node" returns the same type instance '.
|
'Make sure that `resolveType` function of abstract type "Node" returns the same type instance ' .
|
||||||
'as referenced anywhere else within the schema '.
|
'as referenced anywhere else within the schema ' .
|
||||||
'(see http://webonyx.github.io/graphql-php/type-system/#type-registry).',
|
'(see http://webonyx.github.io/graphql-php/type-system/#type-registry).',
|
||||||
$result->errors[0]->getMessage()
|
$result->errors[0]->getMessage()
|
||||||
);
|
);
|
||||||
|
@ -1,33 +1,44 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Executor;
|
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\ResolveInfo;
|
use GraphQL\Type\Definition\ResolveInfo;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function in_array;
|
||||||
|
|
||||||
class DeferredFieldsTest extends TestCase
|
class DeferredFieldsTest extends TestCase
|
||||||
{
|
{
|
||||||
|
/** @var ObjectType */
|
||||||
private $userType;
|
private $userType;
|
||||||
|
|
||||||
|
/** @var ObjectType */
|
||||||
private $storyType;
|
private $storyType;
|
||||||
|
|
||||||
|
/** @var ObjectType */
|
||||||
private $categoryType;
|
private $categoryType;
|
||||||
|
|
||||||
|
/** @var */
|
||||||
private $path;
|
private $path;
|
||||||
|
|
||||||
|
/** @var mixed[][] */
|
||||||
private $storyDataSource;
|
private $storyDataSource;
|
||||||
|
|
||||||
|
/** @var mixed[][] */
|
||||||
private $userDataSource;
|
private $userDataSource;
|
||||||
|
|
||||||
|
/** @var mixed[][] */
|
||||||
private $categoryDataSource;
|
private $categoryDataSource;
|
||||||
|
|
||||||
|
/** @var ObjectType */
|
||||||
private $queryType;
|
private $queryType;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -54,36 +65,41 @@ class DeferredFieldsTest extends TestCase
|
|||||||
$this->categoryDataSource = [
|
$this->categoryDataSource = [
|
||||||
['id' => 1, 'name' => 'Category #1', 'topStoryId' => 8],
|
['id' => 1, 'name' => 'Category #1', 'topStoryId' => 8],
|
||||||
['id' => 2, 'name' => 'Category #2', 'topStoryId' => 3],
|
['id' => 2, 'name' => 'Category #2', 'topStoryId' => 3],
|
||||||
['id' => 3, 'name' => 'Category #3', 'topStoryId' => 9]
|
['id' => 3, 'name' => 'Category #3', 'topStoryId' => 9],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->path = [];
|
$this->path = [];
|
||||||
$this->userType = new ObjectType([
|
$this->userType = new ObjectType([
|
||||||
'name' => 'User',
|
'name' => 'User',
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
'name' => [
|
'name' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($user, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($user, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return $user['name'];
|
return $user['name'];
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'bestFriend' => [
|
'bestFriend' => [
|
||||||
'type' => $this->userType,
|
'type' => $this->userType,
|
||||||
'resolve' => function($user, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($user, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return new Deferred(function() use ($user) {
|
return new Deferred(function () use ($user) {
|
||||||
$this->path[] = 'deferred-for-best-friend-of-' . $user['id'];
|
$this->path[] = 'deferred-for-best-friend-of-' . $user['id'];
|
||||||
return Utils::find($this->userDataSource, function($entry) use ($user) {
|
|
||||||
|
return Utils::find(
|
||||||
|
$this->userDataSource,
|
||||||
|
function ($entry) use ($user) {
|
||||||
return $entry['id'] === $user['bestFriendId'];
|
return $entry['id'] === $user['bestFriendId'];
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
]
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->storyType = new ObjectType([
|
$this->storyType = new ObjectType([
|
||||||
@ -91,25 +107,30 @@ class DeferredFieldsTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'title' => [
|
'title' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function($entry, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($entry, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return $entry['title'];
|
return $entry['title'];
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'author' => [
|
'author' => [
|
||||||
'type' => $this->userType,
|
'type' => $this->userType,
|
||||||
'resolve' => function($story, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($story, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return new Deferred(function() use ($story) {
|
return new Deferred(function () use ($story) {
|
||||||
$this->path[] = 'deferred-for-story-' . $story['id'] . '-author';
|
$this->path[] = 'deferred-for-story-' . $story['id'] . '-author';
|
||||||
return Utils::find($this->userDataSource, function($entry) use ($story) {
|
|
||||||
|
return Utils::find(
|
||||||
|
$this->userDataSource,
|
||||||
|
function ($entry) use ($story) {
|
||||||
return $entry['id'] === $story['authorId'];
|
return $entry['id'] === $story['authorId'];
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
]
|
);
|
||||||
]
|
});
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->categoryType = new ObjectType([
|
$this->categoryType = new ObjectType([
|
||||||
@ -117,35 +138,44 @@ class DeferredFieldsTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => [
|
'name' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function($category, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($category, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return $category['name'];
|
return $category['name'];
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
'stories' => [
|
'stories' => [
|
||||||
'type' => Type::listOf($this->storyType),
|
'type' => Type::listOf($this->storyType),
|
||||||
'resolve' => function($category, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($category, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
return Utils::filter($this->storyDataSource, function($story) use ($category) {
|
|
||||||
|
return Utils::filter(
|
||||||
|
$this->storyDataSource,
|
||||||
|
function ($story) use ($category) {
|
||||||
return in_array($category['id'], $story['categoryIds']);
|
return in_array($category['id'], $story['categoryIds']);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'topStory' => [
|
'topStory' => [
|
||||||
'type' => $this->storyType,
|
'type' => $this->storyType,
|
||||||
'resolve' => function($category, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($category, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return new Deferred(function () use ($category) {
|
return new Deferred(function () use ($category) {
|
||||||
$this->path[] = 'deferred-for-category-' . $category['id'] . '-topStory';
|
$this->path[] = 'deferred-for-category-' . $category['id'] . '-topStory';
|
||||||
return Utils::find($this->storyDataSource, function($story) use ($category) {
|
|
||||||
|
return Utils::find(
|
||||||
|
$this->storyDataSource,
|
||||||
|
function ($story) use ($category) {
|
||||||
return $story['id'] === $category['topStoryId'];
|
return $story['id'] === $category['topStoryId'];
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
]
|
);
|
||||||
]
|
});
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->queryType = new ObjectType([
|
$this->queryType = new ObjectType([
|
||||||
@ -153,28 +183,34 @@ class DeferredFieldsTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'topStories' => [
|
'topStories' => [
|
||||||
'type' => Type::listOf($this->storyType),
|
'type' => Type::listOf($this->storyType),
|
||||||
'resolve' => function($val, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($val, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
return Utils::filter($this->storyDataSource, function($story) {
|
|
||||||
|
return Utils::filter(
|
||||||
|
$this->storyDataSource,
|
||||||
|
function ($story) {
|
||||||
return $story['id'] % 2 === 1;
|
return $story['id'] % 2 === 1;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'featuredCategory' => [
|
'featuredCategory' => [
|
||||||
'type' => $this->categoryType,
|
'type' => $this->categoryType,
|
||||||
'resolve' => function($val, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($val, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return $this->categoryDataSource[0];
|
return $this->categoryDataSource[0];
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'categories' => [
|
'categories' => [
|
||||||
'type' => Type::listOf($this->categoryType),
|
'type' => Type::listOf($this->categoryType),
|
||||||
'resolve' => function($val, $args, $context, ResolveInfo $info) {
|
'resolve' => function ($val, $args, $context, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return $this->categoryDataSource;
|
return $this->categoryDataSource;
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
@ -202,7 +238,7 @@ class DeferredFieldsTest extends TestCase
|
|||||||
');
|
');
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->queryType
|
'query' => $this->queryType,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
@ -220,9 +256,9 @@ class DeferredFieldsTest extends TestCase
|
|||||||
['title' => 'Story #4', 'author' => ['name' => 'Joe']],
|
['title' => 'Story #4', 'author' => ['name' => 'Joe']],
|
||||||
['title' => 'Story #6', 'author' => ['name' => 'Jane']],
|
['title' => 'Story #6', 'author' => ['name' => 'Jane']],
|
||||||
['title' => 'Story #8', 'author' => ['name' => 'John']],
|
['title' => 'Story #8', 'author' => ['name' => 'John']],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = Executor::execute($schema, $query);
|
$result = Executor::execute($schema, $query);
|
||||||
@ -292,7 +328,7 @@ class DeferredFieldsTest extends TestCase
|
|||||||
');
|
');
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->queryType
|
'query' => $this->queryType,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$author1 = ['name' => 'John', 'bestFriend' => ['name' => 'Dirk']];
|
$author1 = ['name' => 'John', 'bestFriend' => ['name' => 'Dirk']];
|
||||||
@ -306,8 +342,8 @@ class DeferredFieldsTest extends TestCase
|
|||||||
['name' => 'Category #1', 'topStory' => ['title' => 'Story #8', 'author' => $author1]],
|
['name' => 'Category #1', 'topStory' => ['title' => 'Story #8', 'author' => $author1]],
|
||||||
['name' => 'Category #2', 'topStory' => ['title' => 'Story #3', 'author' => $author3]],
|
['name' => 'Category #2', 'topStory' => ['title' => 'Story #3', 'author' => $author3]],
|
||||||
['name' => 'Category #3', 'topStory' => ['title' => 'Story #9', 'author' => $author2]],
|
['name' => 'Category #3', 'topStory' => ['title' => 'Story #9', 'author' => $author2]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = Executor::execute($schema, $query);
|
$result = Executor::execute($schema, $query);
|
||||||
@ -353,51 +389,53 @@ class DeferredFieldsTest extends TestCase
|
|||||||
{
|
{
|
||||||
$complexType = new ObjectType([
|
$complexType = new ObjectType([
|
||||||
'name' => 'ComplexType',
|
'name' => 'ComplexType',
|
||||||
'fields' => function() use (&$complexType) {
|
'fields' => function () use (&$complexType) {
|
||||||
return [
|
return [
|
||||||
'sync' => [
|
'sync' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function($v, $a, $c, ResolveInfo $info) {
|
'resolve' => function ($v, $a, $c, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return 'sync';
|
return 'sync';
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'deferred' => [
|
'deferred' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function($v, $a, $c, ResolveInfo $info) {
|
'resolve' => function ($v, $a, $c, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return new Deferred(function() use ($info) {
|
return new Deferred(function () use ($info) {
|
||||||
$this->path[] = ['!dfd for: ', $info->path];
|
$this->path[] = ['!dfd for: ', $info->path];
|
||||||
|
|
||||||
return 'deferred';
|
return 'deferred';
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'nest' => [
|
'nest' => [
|
||||||
'type' => $complexType,
|
'type' => $complexType,
|
||||||
'resolve' => function($v, $a, $c, ResolveInfo $info) {
|
'resolve' => function ($v, $a, $c, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'deferredNest' => [
|
'deferredNest' => [
|
||||||
'type' => $complexType,
|
'type' => $complexType,
|
||||||
'resolve' => function($v, $a, $c, ResolveInfo $info) {
|
'resolve' => function ($v, $a, $c, ResolveInfo $info) {
|
||||||
$this->path[] = $info->path;
|
$this->path[] = $info->path;
|
||||||
|
|
||||||
return new Deferred(function() use ($info) {
|
return new Deferred(function () use ($info) {
|
||||||
$this->path[] = ['!dfd nest for: ', $info->path];
|
$this->path[] = ['!dfd nest for: ', $info->path];
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema(['query' => $complexType]);
|
||||||
'query' => $complexType
|
|
||||||
]);
|
|
||||||
|
|
||||||
$query = Parser::parse('
|
$query = Parser::parse('
|
||||||
{
|
{
|
||||||
@ -435,26 +473,26 @@ class DeferredFieldsTest extends TestCase
|
|||||||
'deferred' => 'deferred',
|
'deferred' => 'deferred',
|
||||||
'nest' => [
|
'nest' => [
|
||||||
'sync' => 'sync',
|
'sync' => 'sync',
|
||||||
'deferred' => 'deferred'
|
'deferred' => 'deferred',
|
||||||
],
|
],
|
||||||
'deferredNest' => [
|
'deferredNest' => [
|
||||||
'sync' => 'sync',
|
'sync' => 'sync',
|
||||||
'deferred' => 'deferred'
|
'deferred' => 'deferred',
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'deferredNest' => [
|
'deferredNest' => [
|
||||||
'sync' => 'sync',
|
'sync' => 'sync',
|
||||||
'deferred' => 'deferred',
|
'deferred' => 'deferred',
|
||||||
'nest' => [
|
'nest' => [
|
||||||
'sync' => 'sync',
|
'sync' => 'sync',
|
||||||
'deferred' => 'deferred'
|
'deferred' => 'deferred',
|
||||||
],
|
],
|
||||||
'deferredNest' => [
|
'deferredNest' => [
|
||||||
'sync' => 'sync',
|
'sync' => 'sync',
|
||||||
'deferred' => 'deferred'
|
'deferred' => 'deferred',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Language\Source;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe: Execute: handles directives
|
||||||
|
*/
|
||||||
class DirectivesTest extends TestCase
|
class DirectivesTest extends TestCase
|
||||||
{
|
{
|
||||||
// Describe: Execute: handles directives
|
/** @var Schema */
|
||||||
|
private static $schema;
|
||||||
|
|
||||||
|
/** @var string[] */
|
||||||
|
private static $data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('basic query works')
|
* @see it('basic query works')
|
||||||
@ -20,10 +31,50 @@ class DirectivesTest extends TestCase
|
|||||||
$this->assertEquals(['data' => ['a' => 'a', 'b' => 'b']], $this->executeTestQuery('{ a, b }'));
|
$this->assertEquals(['data' => ['a' => 'a', 'b' => 'b']], $this->executeTestQuery('{ a, b }'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Source|string $doc
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
private function executeTestQuery($doc) : array
|
||||||
|
{
|
||||||
|
return Executor::execute(self::getSchema(), Parser::parse($doc), self::getData())->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getSchema() : Schema
|
||||||
|
{
|
||||||
|
if (! self::$schema) {
|
||||||
|
self::$schema = new Schema([
|
||||||
|
'query' => new ObjectType([
|
||||||
|
'name' => 'TestType',
|
||||||
|
'fields' => [
|
||||||
|
'a' => ['type' => Type::string()],
|
||||||
|
'b' => ['type' => Type::string()],
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
private static function getData() : array
|
||||||
|
{
|
||||||
|
return self::$data ?: (self::$data = [
|
||||||
|
'a' => 'a',
|
||||||
|
'b' => 'b',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function testWorksOnScalars() : void
|
public function testWorksOnScalars() : void
|
||||||
{
|
{
|
||||||
// if true includes scalar
|
// if true includes scalar
|
||||||
$this->assertEquals(['data' => ['a' => 'a', 'b' => 'b']], $this->executeTestQuery('{ a, b @include(if: true) }'));
|
$this->assertEquals(
|
||||||
|
['data' => ['a' => 'a', 'b' => 'b']],
|
||||||
|
$this->executeTestQuery('{ a, b @include(if: true) }')
|
||||||
|
);
|
||||||
|
|
||||||
// if false omits on scalar
|
// if false omits on scalar
|
||||||
$this->assertEquals(['data' => ['a' => 'a']], $this->executeTestQuery('{ a, b @include(if: false) }'));
|
$this->assertEquals(['data' => ['a' => 'a']], $this->executeTestQuery('{ a, b @include(if: false) }'));
|
||||||
@ -200,37 +251,4 @@ class DirectivesTest extends TestCase
|
|||||||
$this->executeTestQuery('{ a, b @include(if: false) @skip(if: false) }')
|
$this->executeTestQuery('{ a, b @include(if: false) @skip(if: false) }')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static $schema;
|
|
||||||
|
|
||||||
private static $data;
|
|
||||||
|
|
||||||
private static function getSchema()
|
|
||||||
{
|
|
||||||
if (!self::$schema) {
|
|
||||||
self::$schema = new Schema([
|
|
||||||
'query' => new ObjectType([
|
|
||||||
'name' => 'TestType',
|
|
||||||
'fields' => [
|
|
||||||
'a' => ['type' => Type::string()],
|
|
||||||
'b' => ['type' => Type::string()]
|
|
||||||
]
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
return self::$schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function getData()
|
|
||||||
{
|
|
||||||
return self::$data ?: (self::$data = [
|
|
||||||
'a' => 'a',
|
|
||||||
'b' => 'b'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function executeTestQuery($doc)
|
|
||||||
{
|
|
||||||
return Executor::execute(self::getSchema(), Parser::parse($doc), self::getData())->toArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
|
@ -1,44 +1,62 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Executor;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Error\Warning;
|
use GraphQL\Error\Warning;
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Cat;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Dog;
|
||||||
use GraphQL\Type\Definition\CustomScalarType;
|
use GraphQL\Type\Definition\CustomScalarType;
|
||||||
|
use GraphQL\Type\Definition\EnumType;
|
||||||
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
use GraphQL\Type\Definition\ScalarType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\UnionType;
|
use GraphQL\Type\Definition\UnionType;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\Error\Error;
|
use PHPUnit\Framework\Error\Error;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function count;
|
||||||
|
|
||||||
class ExecutorLazySchemaTest extends TestCase
|
class ExecutorLazySchemaTest extends TestCase
|
||||||
{
|
{
|
||||||
public $SomeScalarType;
|
/** @var ScalarType */
|
||||||
|
public $someScalarType;
|
||||||
|
|
||||||
public $SomeObjectType;
|
/** @var ObjectType */
|
||||||
|
public $someObjectType;
|
||||||
|
|
||||||
public $OtherObjectType;
|
/** @var ObjectType */
|
||||||
|
public $otherObjectType;
|
||||||
|
|
||||||
public $DeeperObjectType;
|
/** @var ObjectType */
|
||||||
|
public $deeperObjectType;
|
||||||
|
|
||||||
public $SomeUnionType;
|
/** @var UnionType */
|
||||||
|
public $someUnionType;
|
||||||
|
|
||||||
public $SomeInterfaceType;
|
/** @var InterfaceType */
|
||||||
|
public $someInterfaceType;
|
||||||
|
|
||||||
public $SomeEnumType;
|
/** @var EnumType */
|
||||||
|
public $someEnumType;
|
||||||
|
|
||||||
public $SomeInputObjectType;
|
/** @var InputObjectType */
|
||||||
|
public $someInputObjectType;
|
||||||
|
|
||||||
public $QueryType;
|
/** @var ObjectType */
|
||||||
|
public $queryType;
|
||||||
|
|
||||||
|
/** @var string[] */
|
||||||
public $calls = [];
|
public $calls = [];
|
||||||
|
|
||||||
|
/** @var bool[] */
|
||||||
public $loadedTypes = [];
|
public $loadedTypes = [];
|
||||||
|
|
||||||
public function testWarnsAboutSlowIsTypeOfForLazySchema() : void
|
public function testWarnsAboutSlowIsTypeOfForLazySchema() : void
|
||||||
@ -46,24 +64,26 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
// isTypeOf used to resolve runtime type for Interface
|
// isTypeOf used to resolve runtime type for Interface
|
||||||
$petType = new InterfaceType([
|
$petType = new InterfaceType([
|
||||||
'name' => 'Pet',
|
'name' => 'Pet',
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Added to interface type when defined
|
// Added to interface type when defined
|
||||||
$dogType = new ObjectType([
|
$dogType = new ObjectType([
|
||||||
'name' => 'Dog',
|
'name' => 'Dog',
|
||||||
'interfaces' => [$petType],
|
'interfaces' => [$petType],
|
||||||
'isTypeOf' => function($obj) { return $obj instanceof Dog; },
|
'isTypeOf' => function ($obj) {
|
||||||
'fields' => function() {
|
return $obj instanceof Dog;
|
||||||
|
},
|
||||||
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()]
|
'woofs' => ['type' => Type::boolean()],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$catType = new ObjectType([
|
$catType = new ObjectType([
|
||||||
@ -72,12 +92,12 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
'isTypeOf' => function ($obj) {
|
'isTypeOf' => function ($obj) {
|
||||||
return $obj instanceof Cat;
|
return $obj instanceof Cat;
|
||||||
},
|
},
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()],
|
'meows' => ['type' => Type::boolean()],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -88,12 +108,12 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
'type' => Type::listOf($petType),
|
'type' => Type::listOf($petType),
|
||||||
'resolve' => function () {
|
'resolve' => function () {
|
||||||
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
return [new Dog('Odie', true), new Cat('Garfield', false)];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$catType, $dogType],
|
'types' => [$catType, $dogType],
|
||||||
'typeLoader' => function($name) use ($dogType, $petType, $catType) {
|
'typeLoader' => function ($name) use ($dogType, $petType, $catType) {
|
||||||
switch ($name) {
|
switch ($name) {
|
||||||
case 'Dog':
|
case 'Dog':
|
||||||
return $dogType;
|
return $dogType;
|
||||||
@ -102,7 +122,7 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
case 'Cat':
|
case 'Cat':
|
||||||
return $catType;
|
return $catType;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{
|
$query = '{
|
||||||
@ -120,7 +140,7 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
$expected = new ExecutionResult([
|
$expected = new ExecutionResult([
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['name' => 'Odie', 'woofs' => true],
|
['name' => 'Odie', 'woofs' => true],
|
||||||
['name' => 'Garfield', 'meows' => false]
|
['name' => 'Garfield', 'meows' => false],
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -134,43 +154,46 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
$this->assertInstanceOf(Error::class, $result->errors[0]->getPrevious());
|
$this->assertInstanceOf(Error::class, $result->errors[0]->getPrevious());
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'GraphQL Interface Type `Pet` returned `null` from it`s `resolveType` function for value: instance of '.
|
'GraphQL Interface Type `Pet` returned `null` from it`s `resolveType` function for value: instance of ' .
|
||||||
'GraphQL\Tests\Executor\Dog. Switching to slow resolution method using `isTypeOf` of all possible '.
|
'GraphQL\Tests\Executor\TestClasses\Dog. Switching to slow resolution method using `isTypeOf` of all possible ' .
|
||||||
'implementations. It requires full schema scan and degrades query performance significantly. '.
|
'implementations. It requires full schema scan and degrades query performance significantly. ' .
|
||||||
'Make sure your `resolveType` always returns valid implementation or throws.',
|
'Make sure your `resolveType` always returns valid implementation or throws.',
|
||||||
$result->errors[0]->getMessage());
|
$result->errors[0]->getMessage()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHintsOnConflictingTypeInstancesInDefinitions() : void
|
public function testHintsOnConflictingTypeInstancesInDefinitions() : void
|
||||||
{
|
{
|
||||||
$calls = [];
|
$calls = [];
|
||||||
$typeLoader = function($name) use (&$calls) {
|
$typeLoader = function ($name) use (&$calls) {
|
||||||
$calls[] = $name;
|
$calls[] = $name;
|
||||||
switch ($name) {
|
switch ($name) {
|
||||||
case 'Test':
|
case 'Test':
|
||||||
return new ObjectType([
|
return new ObjectType([
|
||||||
'name' => 'Test',
|
'name' => 'Test',
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
'test' => Type::string(),
|
'test' => Type::string(),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => function() use ($typeLoader) {
|
'fields' => function () use ($typeLoader) {
|
||||||
return [
|
return [
|
||||||
'test' => $typeLoader('Test')
|
'test' => $typeLoader('Test'),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'typeLoader' => $typeLoader
|
'typeLoader' => $typeLoader,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '
|
$query = '
|
||||||
@ -186,8 +209,8 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
$this->assertEquals(['Test', 'Test'], $calls);
|
$this->assertEquals(['Test', 'Test'], $calls);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'Schema must contain unique named types but contains multiple types named "Test". '.
|
'Schema must contain unique named types but contains multiple types named "Test". ' .
|
||||||
'Make sure that type loader returns the same instance as defined in Query.test '.
|
'Make sure that type loader returns the same instance as defined in Query.test ' .
|
||||||
'(see http://webonyx.github.io/graphql-php/type-system/#type-registry).',
|
'(see http://webonyx.github.io/graphql-php/type-system/#type-registry).',
|
||||||
$result->errors[0]->getMessage()
|
$result->errors[0]->getMessage()
|
||||||
);
|
);
|
||||||
@ -201,9 +224,9 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->loadType('Query'),
|
'query' => $this->loadType('Query'),
|
||||||
'typeLoader' => function($name) {
|
'typeLoader' => function ($name) {
|
||||||
return $this->loadType($name, true);
|
return $this->loadType($name, true);
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{ object { string } }';
|
$query = '{ object { string } }';
|
||||||
@ -219,19 +242,126 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
$expectedExecutorCalls = [
|
$expectedExecutorCalls = [
|
||||||
'Query.fields',
|
'Query.fields',
|
||||||
'SomeObject',
|
'SomeObject',
|
||||||
'SomeObject.fields'
|
'SomeObject.fields',
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray(true));
|
$this->assertEquals($expected, $result->toArray(true));
|
||||||
$this->assertEquals($expectedExecutorCalls, $this->calls);
|
$this->assertEquals($expectedExecutorCalls, $this->calls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function loadType($name, $isExecutorCall = false)
|
||||||
|
{
|
||||||
|
if ($isExecutorCall) {
|
||||||
|
$this->calls[] = $name;
|
||||||
|
}
|
||||||
|
$this->loadedTypes[$name] = true;
|
||||||
|
|
||||||
|
switch ($name) {
|
||||||
|
case 'Query':
|
||||||
|
return $this->queryType ?: $this->queryType = new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => function () {
|
||||||
|
$this->calls[] = 'Query.fields';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'object' => ['type' => $this->loadType('SomeObject')],
|
||||||
|
'other' => ['type' => $this->loadType('OtherObject')],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'SomeObject':
|
||||||
|
return $this->someObjectType ?: $this->someObjectType = new ObjectType([
|
||||||
|
'name' => 'SomeObject',
|
||||||
|
'fields' => function () {
|
||||||
|
$this->calls[] = 'SomeObject.fields';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'string' => ['type' => Type::string()],
|
||||||
|
'object' => ['type' => $this->someObjectType],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
'interfaces' => function () {
|
||||||
|
$this->calls[] = 'SomeObject.interfaces';
|
||||||
|
|
||||||
|
return [
|
||||||
|
$this->loadType('SomeInterface'),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'OtherObject':
|
||||||
|
return $this->otherObjectType ?: $this->otherObjectType = new ObjectType([
|
||||||
|
'name' => 'OtherObject',
|
||||||
|
'fields' => function () {
|
||||||
|
$this->calls[] = 'OtherObject.fields';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'union' => ['type' => $this->loadType('SomeUnion')],
|
||||||
|
'iface' => ['type' => Type::nonNull($this->loadType('SomeInterface'))],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'DeeperObject':
|
||||||
|
return $this->deeperObjectType ?: $this->deeperObjectType = new ObjectType([
|
||||||
|
'name' => 'DeeperObject',
|
||||||
|
'fields' => function () {
|
||||||
|
return [
|
||||||
|
'scalar' => ['type' => $this->loadType('SomeScalar')],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'SomeScalar':
|
||||||
|
return $this->someScalarType ?: $this->someScalarType = new CustomScalarType([
|
||||||
|
'name' => 'SomeScalar',
|
||||||
|
'serialize' => function ($value) {
|
||||||
|
return $value;
|
||||||
|
},
|
||||||
|
'parseValue' => function ($value) {
|
||||||
|
return $value;
|
||||||
|
},
|
||||||
|
'parseLiteral' => function () {
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'SomeUnion':
|
||||||
|
return $this->someUnionType ?: $this->someUnionType = new UnionType([
|
||||||
|
'name' => 'SomeUnion',
|
||||||
|
'resolveType' => function () {
|
||||||
|
$this->calls[] = 'SomeUnion.resolveType';
|
||||||
|
|
||||||
|
return $this->loadType('DeeperObject');
|
||||||
|
},
|
||||||
|
'types' => function () {
|
||||||
|
$this->calls[] = 'SomeUnion.types';
|
||||||
|
|
||||||
|
return [$this->loadType('DeeperObject')];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
case 'SomeInterface':
|
||||||
|
return $this->someInterfaceType ?: $this->someInterfaceType = new InterfaceType([
|
||||||
|
'name' => 'SomeInterface',
|
||||||
|
'resolveType' => function () {
|
||||||
|
$this->calls[] = 'SomeInterface.resolveType';
|
||||||
|
|
||||||
|
return $this->loadType('SomeObject');
|
||||||
|
},
|
||||||
|
'fields' => function () {
|
||||||
|
$this->calls[] = 'SomeInterface.fields';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'string' => ['type' => Type::string()],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function testDeepQuery() : void
|
public function testDeepQuery() : void
|
||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->loadType('Query'),
|
'query' => $this->loadType('Query'),
|
||||||
'typeLoader' => function($name) {
|
'typeLoader' => function ($name) {
|
||||||
return $this->loadType($name, true);
|
return $this->loadType($name, true);
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '{ object { object { object { string } } } }';
|
$query = '{ object { object { object { string } } } }';
|
||||||
@ -242,12 +372,12 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
);
|
);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => ['object' => ['object' => ['object' => ['string' => 'test']]]]
|
'data' => ['object' => ['object' => ['object' => ['string' => 'test']]]],
|
||||||
];
|
];
|
||||||
$expectedLoadedTypes = [
|
$expectedLoadedTypes = [
|
||||||
'Query' => true,
|
'Query' => true,
|
||||||
'SomeObject' => true,
|
'SomeObject' => true,
|
||||||
'OtherObject' => true
|
'OtherObject' => true,
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray(true));
|
$this->assertEquals($expected, $result->toArray(true));
|
||||||
@ -256,7 +386,7 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
$expectedExecutorCalls = [
|
$expectedExecutorCalls = [
|
||||||
'Query.fields',
|
'Query.fields',
|
||||||
'SomeObject',
|
'SomeObject',
|
||||||
'SomeObject.fields'
|
'SomeObject.fields',
|
||||||
];
|
];
|
||||||
$this->assertEquals($expectedExecutorCalls, $this->calls);
|
$this->assertEquals($expectedExecutorCalls, $this->calls);
|
||||||
}
|
}
|
||||||
@ -265,9 +395,9 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->loadType('Query'),
|
'query' => $this->loadType('Query'),
|
||||||
'typeLoader' => function($name) {
|
'typeLoader' => function ($name) {
|
||||||
return $this->loadType($name, true);
|
return $this->loadType($name, true);
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = '
|
$query = '
|
||||||
@ -313,98 +443,4 @@ class ExecutorLazySchemaTest extends TestCase
|
|||||||
];
|
];
|
||||||
$this->assertEquals($expectedCalls, $this->calls);
|
$this->assertEquals($expectedCalls, $this->calls);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadType($name, $isExecutorCall = false)
|
|
||||||
{
|
|
||||||
if ($isExecutorCall) {
|
|
||||||
$this->calls[] = $name;
|
|
||||||
}
|
|
||||||
$this->loadedTypes[$name] = true;
|
|
||||||
|
|
||||||
switch ($name) {
|
|
||||||
case 'Query':
|
|
||||||
return $this->QueryType ?: $this->QueryType = new ObjectType([
|
|
||||||
'name' => 'Query',
|
|
||||||
'fields' => function() {
|
|
||||||
$this->calls[] = 'Query.fields';
|
|
||||||
return [
|
|
||||||
'object' => ['type' => $this->loadType('SomeObject')],
|
|
||||||
'other' => ['type' => $this->loadType('OtherObject')],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
case 'SomeObject':
|
|
||||||
return $this->SomeObjectType ?: $this->SomeObjectType = new ObjectType([
|
|
||||||
'name' => 'SomeObject',
|
|
||||||
'fields' => function() {
|
|
||||||
$this->calls[] = 'SomeObject.fields';
|
|
||||||
return [
|
|
||||||
'string' => ['type' => Type::string()],
|
|
||||||
'object' => ['type' => $this->SomeObjectType]
|
|
||||||
];
|
|
||||||
},
|
|
||||||
'interfaces' => function() {
|
|
||||||
$this->calls[] = 'SomeObject.interfaces';
|
|
||||||
return [
|
|
||||||
$this->loadType('SomeInterface')
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
case 'OtherObject':
|
|
||||||
return $this->OtherObjectType ?: $this->OtherObjectType = new ObjectType([
|
|
||||||
'name' => 'OtherObject',
|
|
||||||
'fields' => function() {
|
|
||||||
$this->calls[] = 'OtherObject.fields';
|
|
||||||
return [
|
|
||||||
'union' => ['type' => $this->loadType('SomeUnion')],
|
|
||||||
'iface' => ['type' => Type::nonNull($this->loadType('SomeInterface'))],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
case 'DeeperObject':
|
|
||||||
return $this->DeeperObjectType ?: $this->DeeperObjectType = new ObjectType([
|
|
||||||
'name' => 'DeeperObject',
|
|
||||||
'fields' => function() {
|
|
||||||
return [
|
|
||||||
'scalar' => ['type' => $this->loadType('SomeScalar')],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
case 'SomeScalar';
|
|
||||||
return $this->SomeScalarType ?: $this->SomeScalarType = new CustomScalarType([
|
|
||||||
'name' => 'SomeScalar',
|
|
||||||
'serialize' => function($value) {return $value;},
|
|
||||||
'parseValue' => function($value) {return $value;},
|
|
||||||
'parseLiteral' => function() {}
|
|
||||||
]);
|
|
||||||
case 'SomeUnion':
|
|
||||||
return $this->SomeUnionType ?: $this->SomeUnionType = new UnionType([
|
|
||||||
'name' => 'SomeUnion',
|
|
||||||
'resolveType' => function() {
|
|
||||||
$this->calls[] = 'SomeUnion.resolveType';
|
|
||||||
return $this->loadType('DeeperObject');
|
|
||||||
},
|
|
||||||
'types' => function() {
|
|
||||||
$this->calls[] = 'SomeUnion.types';
|
|
||||||
return [ $this->loadType('DeeperObject') ];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
case 'SomeInterface':
|
|
||||||
return $this->SomeInterfaceType ?: $this->SomeInterfaceType = new InterfaceType([
|
|
||||||
'name' => 'SomeInterface',
|
|
||||||
'resolveType' => function() {
|
|
||||||
$this->calls[] = 'SomeInterface.resolveType';
|
|
||||||
return $this->loadType('SomeObject');
|
|
||||||
},
|
|
||||||
'fields' => function() {
|
|
||||||
$this->calls[] = 'SomeInterface.fields';
|
|
||||||
return [
|
|
||||||
'string' => ['type' => Type::string() ]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function sprintf;
|
||||||
|
|
||||||
class ExecutorSchemaTest extends TestCase
|
class ExecutorSchemaTest extends TestCase
|
||||||
{
|
{
|
||||||
// Execute: Handles execution with a complex schema
|
// Execute: Handles execution with a complex schema
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('executes using a schema')
|
* @see it('executes using a schema')
|
||||||
*/
|
*/
|
||||||
@ -24,12 +27,12 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'url' => ['type' => Type::string()],
|
'url' => ['type' => Type::string()],
|
||||||
'width' => ['type' => Type::int()],
|
'width' => ['type' => Type::int()],
|
||||||
'height' => ['type' => Type::int()],
|
'height' => ['type' => Type::int()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$BlogAuthor = new ObjectType([
|
$BlogAuthor = new ObjectType([
|
||||||
'name' => 'Author',
|
'name' => 'Author',
|
||||||
'fields' => function() use (&$BlogArticle, &$BlogImage) {
|
'fields' => function () use (&$BlogArticle, &$BlogImage) {
|
||||||
return [
|
return [
|
||||||
'id' => ['type' => Type::string()],
|
'id' => ['type' => Type::string()],
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
@ -38,11 +41,11 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'type' => $BlogImage,
|
'type' => $BlogImage,
|
||||||
'resolve' => function ($obj, $args) {
|
'resolve' => function ($obj, $args) {
|
||||||
return $obj['pic']($args['width'], $args['height']);
|
return $obj['pic']($args['width'], $args['height']);
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'recentArticle' => $BlogArticle
|
'recentArticle' => $BlogArticle,
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$BlogArticle = new ObjectType([
|
$BlogArticle = new ObjectType([
|
||||||
@ -53,8 +56,8 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'author' => ['type' => $BlogAuthor],
|
'author' => ['type' => $BlogAuthor],
|
||||||
'title' => ['type' => Type::string()],
|
'title' => ['type' => Type::string()],
|
||||||
'body' => ['type' => Type::string()],
|
'body' => ['type' => Type::string()],
|
||||||
'keywords' => ['type' => Type::listOf(Type::string())]
|
'keywords' => ['type' => Type::listOf(Type::string())],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$BlogQuery = new ObjectType([
|
$BlogQuery = new ObjectType([
|
||||||
@ -65,7 +68,7 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'args' => ['id' => ['type' => Type::id()]],
|
'args' => ['id' => ['type' => Type::id()]],
|
||||||
'resolve' => function ($_, $args) {
|
'resolve' => function ($_, $args) {
|
||||||
return $this->article($args['id']);
|
return $this->article($args['id']);
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'feed' => [
|
'feed' => [
|
||||||
'type' => Type::listOf($BlogArticle),
|
'type' => Type::listOf($BlogArticle),
|
||||||
@ -80,16 +83,15 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
$this->article(7),
|
$this->article(7),
|
||||||
$this->article(8),
|
$this->article(8),
|
||||||
$this->article(9),
|
$this->article(9),
|
||||||
$this->article(10)
|
$this->article(10),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$BlogSchema = new Schema(['query' => $BlogQuery]);
|
$BlogSchema = new Schema(['query' => $BlogQuery]);
|
||||||
|
|
||||||
|
|
||||||
$request = '
|
$request = '
|
||||||
{
|
{
|
||||||
feed {
|
feed {
|
||||||
@ -127,26 +129,46 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'feed' => [
|
'feed' => [
|
||||||
['id' => '1',
|
[
|
||||||
'title' => 'My Article 1'],
|
'id' => '1',
|
||||||
['id' => '2',
|
'title' => 'My Article 1',
|
||||||
'title' => 'My Article 2'],
|
],
|
||||||
['id' => '3',
|
[
|
||||||
'title' => 'My Article 3'],
|
'id' => '2',
|
||||||
['id' => '4',
|
'title' => 'My Article 2',
|
||||||
'title' => 'My Article 4'],
|
],
|
||||||
['id' => '5',
|
[
|
||||||
'title' => 'My Article 5'],
|
'id' => '3',
|
||||||
['id' => '6',
|
'title' => 'My Article 3',
|
||||||
'title' => 'My Article 6'],
|
],
|
||||||
['id' => '7',
|
[
|
||||||
'title' => 'My Article 7'],
|
'id' => '4',
|
||||||
['id' => '8',
|
'title' => 'My Article 4',
|
||||||
'title' => 'My Article 8'],
|
],
|
||||||
['id' => '9',
|
[
|
||||||
'title' => 'My Article 9'],
|
'id' => '5',
|
||||||
['id' => '10',
|
'title' => 'My Article 5',
|
||||||
'title' => 'My Article 10']
|
],
|
||||||
|
[
|
||||||
|
'id' => '6',
|
||||||
|
'title' => 'My Article 6',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '7',
|
||||||
|
'title' => 'My Article 7',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '8',
|
||||||
|
'title' => 'My Article 8',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '9',
|
||||||
|
'title' => 'My Article 9',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '10',
|
||||||
|
'title' => 'My Article 10',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'article' => [
|
'article' => [
|
||||||
'id' => '1',
|
'id' => '1',
|
||||||
@ -159,18 +181,18 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'pic' => [
|
'pic' => [
|
||||||
'url' => 'cdn://123',
|
'url' => 'cdn://123',
|
||||||
'width' => 640,
|
'width' => 640,
|
||||||
'height' => 480
|
'height' => 480,
|
||||||
],
|
],
|
||||||
'recentArticle' => [
|
'recentArticle' => [
|
||||||
'id' => '1',
|
'id' => '1',
|
||||||
'isPublished' => true,
|
'isPublished' => true,
|
||||||
'title' => 'My Article 1',
|
'title' => 'My Article 1',
|
||||||
'body' => 'This is a post',
|
'body' => 'This is a post',
|
||||||
'keywords' => ['foo', 'bar', '1', 'true', null]
|
'keywords' => ['foo', 'bar', '1', 'true', null],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($BlogSchema, Parser::parse($request))->toArray());
|
$this->assertEquals($expected, Executor::execute($BlogSchema, Parser::parse($request))->toArray());
|
||||||
@ -179,7 +201,7 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
private function article($id)
|
private function article($id)
|
||||||
{
|
{
|
||||||
$johnSmith = null;
|
$johnSmith = null;
|
||||||
$article = function($id) use (&$johnSmith) {
|
$article = function ($id) use (&$johnSmith) {
|
||||||
return [
|
return [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'isPublished' => 'true',
|
'isPublished' => 'true',
|
||||||
@ -187,22 +209,24 @@ class ExecutorSchemaTest extends TestCase
|
|||||||
'title' => 'My Article ' . $id,
|
'title' => 'My Article ' . $id,
|
||||||
'body' => 'This is a post',
|
'body' => 'This is a post',
|
||||||
'hidden' => 'This data is not exposed in the schema',
|
'hidden' => 'This data is not exposed in the schema',
|
||||||
'keywords' => ['foo', 'bar', 1, true, null]
|
'keywords' => ['foo', 'bar', 1, true, null],
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
$getPic = function($uid, $width, $height) {
|
$getPic = function ($uid, $width, $height) {
|
||||||
return [
|
return [
|
||||||
'url' => "cdn://$uid",
|
'url' => sprintf('cdn://%s', $uid),
|
||||||
'width' => $width,
|
'width' => $width,
|
||||||
'height' => $height
|
'height' => $height,
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
$johnSmith = [
|
$johnSmith = [
|
||||||
'id' => 123,
|
'id' => 123,
|
||||||
'name' => 'John Smith',
|
'name' => 'John Smith',
|
||||||
'pic' => function($width, $height) use ($getPic) {return $getPic(123, $width, $height);},
|
'pic' => function ($width, $height) use ($getPic) {
|
||||||
|
return $getPic(123, $width, $height);
|
||||||
|
},
|
||||||
'recentArticle' => $article(1),
|
'recentArticle' => $article(1),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,104 +1,34 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author: Ivo Meißner
|
* @author: Ivo Meißner
|
||||||
* Date: 03.05.16
|
* Date: 03.05.16
|
||||||
* Time: 13:14
|
* Time: 13:14
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class LazyInterfaceTest extends TestCase
|
class LazyInterfaceTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var Schema */
|
||||||
* @var Schema
|
|
||||||
*/
|
|
||||||
protected $schema;
|
protected $schema;
|
||||||
|
|
||||||
/**
|
/** @var InterfaceType */
|
||||||
* @var InterfaceType
|
|
||||||
*/
|
|
||||||
protected $lazyInterface;
|
protected $lazyInterface;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
protected $testObject;
|
protected $testObject;
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup schema
|
|
||||||
*/
|
|
||||||
protected function setUp()
|
|
||||||
{
|
|
||||||
$query = new ObjectType([
|
|
||||||
'name' => 'query',
|
|
||||||
'fields' => function () {
|
|
||||||
return [
|
|
||||||
'lazyInterface' => [
|
|
||||||
'type' => $this->getLazyInterfaceType(),
|
|
||||||
'resolve' => function() {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->schema = new Schema(['query' => $query, 'types' => [$this->getTestObjectType()]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the LazyInterface
|
|
||||||
*
|
|
||||||
* @return InterfaceType
|
|
||||||
*/
|
|
||||||
protected function getLazyInterfaceType()
|
|
||||||
{
|
|
||||||
if (!$this->lazyInterface) {
|
|
||||||
$this->lazyInterface = new InterfaceType([
|
|
||||||
'name' => 'LazyInterface',
|
|
||||||
'fields' => [
|
|
||||||
'a' => Type::string()
|
|
||||||
],
|
|
||||||
'resolveType' => function() {
|
|
||||||
return $this->getTestObjectType();
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->lazyInterface;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the test ObjectType
|
|
||||||
* @return ObjectType
|
|
||||||
*/
|
|
||||||
protected function getTestObjectType()
|
|
||||||
{
|
|
||||||
if (!$this->testObject) {
|
|
||||||
$this->testObject = new ObjectType([
|
|
||||||
'name' => 'TestObject',
|
|
||||||
'fields' => [
|
|
||||||
'name' => [
|
|
||||||
'type' => Type::string(),
|
|
||||||
'resolve' => function() {
|
|
||||||
return 'testname';
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'interfaces' => [$this->getLazyInterfaceType()]
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->testObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles execution of a lazily created interface
|
* Handles execution of a lazily created interface
|
||||||
*/
|
*/
|
||||||
@ -116,12 +46,78 @@ class LazyInterfaceTest extends TestCase
|
|||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'lazyInterface' => [
|
'lazyInterface' => ['name' => 'testname'],
|
||||||
'name' => 'testname'
|
],
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, Parser::parse($request))->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema, Parser::parse($request))->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup schema
|
||||||
|
*/
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$query = new ObjectType([
|
||||||
|
'name' => 'query',
|
||||||
|
'fields' => function () {
|
||||||
|
return [
|
||||||
|
'lazyInterface' => [
|
||||||
|
'type' => $this->getLazyInterfaceType(),
|
||||||
|
'resolve' => function () {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->schema = new Schema(['query' => $query, 'types' => [$this->getTestObjectType()]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the LazyInterface
|
||||||
|
*
|
||||||
|
* @return InterfaceType
|
||||||
|
*/
|
||||||
|
protected function getLazyInterfaceType()
|
||||||
|
{
|
||||||
|
if (! $this->lazyInterface) {
|
||||||
|
$this->lazyInterface = new InterfaceType([
|
||||||
|
'name' => 'LazyInterface',
|
||||||
|
'fields' => [
|
||||||
|
'a' => Type::string(),
|
||||||
|
],
|
||||||
|
'resolveType' => function () {
|
||||||
|
return $this->getTestObjectType();
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->lazyInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the test ObjectType
|
||||||
|
* @return ObjectType
|
||||||
|
*/
|
||||||
|
protected function getTestObjectType()
|
||||||
|
{
|
||||||
|
if (! $this->testObject) {
|
||||||
|
$this->testObject = new ObjectType([
|
||||||
|
'name' => 'TestObject',
|
||||||
|
'fields' => [
|
||||||
|
'name' => [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'resolve' => function () {
|
||||||
|
return 'testname';
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'interfaces' => [$this->getLazyInterfaceType()],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->testObject;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
use GraphQL\Error\UserError;
|
use GraphQL\Error\UserError;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Error\FormattedError;
|
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\SourceLocation;
|
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class ListsTest extends TestCase
|
class ListsTest extends TestCase
|
||||||
{
|
{
|
||||||
// Describe: Execute: Handles list nullability
|
// Describe: Execute: Handles list nullability
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [T]
|
* [T]
|
||||||
*/
|
*/
|
||||||
@ -24,23 +23,57 @@ class ListsTest extends TestCase
|
|||||||
{
|
{
|
||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesNullableLists(
|
$this->checkHandlesNullableLists(
|
||||||
[ 1, 2 ],
|
[1, 2],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesNullableLists(
|
$this->checkHandlesNullableLists(
|
||||||
[ 1, null, 2 ],
|
[1, null, 2],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, null, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Returns null
|
// Returns null
|
||||||
$this->checkHandlesNullableLists(
|
$this->checkHandlesNullableLists(
|
||||||
null,
|
null,
|
||||||
[ 'data' => [ 'nest' => [ 'test' => null ] ] ]
|
['data' => ['nest' => ['test' => null]]]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function checkHandlesNullableLists($testData, $expected)
|
||||||
|
{
|
||||||
|
$testType = Type::listOf(Type::int());
|
||||||
|
$this->check($testType, $testData, $expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function check($testType, $testData, $expected, $debug = false)
|
||||||
|
{
|
||||||
|
$data = ['test' => $testData];
|
||||||
|
$dataType = null;
|
||||||
|
|
||||||
|
$dataType = new ObjectType([
|
||||||
|
'name' => 'DataType',
|
||||||
|
'fields' => function () use (&$testType, &$dataType, $data) {
|
||||||
|
return [
|
||||||
|
'test' => ['type' => $testType],
|
||||||
|
'nest' => [
|
||||||
|
'type' => $dataType,
|
||||||
|
'resolve' => function () use ($data) {
|
||||||
|
return $data;
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
$schema = new Schema(['query' => $dataType]);
|
||||||
|
|
||||||
|
$ast = Parser::parse('{ nest { test } }');
|
||||||
|
|
||||||
|
$result = Executor::execute($schema, $ast, $data);
|
||||||
|
$this->assertArraySubset($expected, $result->toArray($debug));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [T]
|
* [T]
|
||||||
*/
|
*/
|
||||||
@ -48,26 +81,26 @@ class ListsTest extends TestCase
|
|||||||
{
|
{
|
||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesNullableLists(
|
$this->checkHandlesNullableLists(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return [1,2];
|
return [1, 2];
|
||||||
}),
|
}),
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesNullableLists(
|
$this->checkHandlesNullableLists(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return [1, null, 2];
|
return [1, null, 2];
|
||||||
}),
|
}),
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, null, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Returns null
|
// Returns null
|
||||||
$this->checkHandlesNullableLists(
|
$this->checkHandlesNullableLists(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
[ 'data' => [ 'nest' => [ 'test' => null ] ] ]
|
['data' => ['nest' => ['test' => null]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Rejected
|
// Rejected
|
||||||
@ -83,9 +116,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test']
|
'path' => ['nest', 'test'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -98,46 +131,53 @@ class ListsTest extends TestCase
|
|||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesNullableLists(
|
$this->checkHandlesNullableLists(
|
||||||
[
|
[
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 1;
|
return 1;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})],
|
}),
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
],
|
||||||
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesNullableLists(
|
$this->checkHandlesNullableLists(
|
||||||
[
|
[
|
||||||
new Deferred(function() {return 1;}),
|
new Deferred(function () {
|
||||||
new Deferred(function() {return null;}),
|
return 1;
|
||||||
new Deferred(function() {return 2;})
|
}),
|
||||||
|
new Deferred(function () {
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
new Deferred(function () {
|
||||||
|
return 2;
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, null, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Returns null
|
// Returns null
|
||||||
$this->checkHandlesNullableLists(
|
$this->checkHandlesNullableLists(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
[ 'data' => [ 'nest' => [ 'test' => null ] ] ]
|
['data' => ['nest' => ['test' => null]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains reject
|
// Contains reject
|
||||||
$this->checkHandlesNullableLists(
|
$this->checkHandlesNullableLists(
|
||||||
function () {
|
function () {
|
||||||
return [
|
return [
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 1;
|
return 1;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
throw new UserError('bad');
|
throw new UserError('bad');
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@ -146,9 +186,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test', 1]
|
'path' => ['nest', 'test', 1],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -160,32 +200,38 @@ class ListsTest extends TestCase
|
|||||||
{
|
{
|
||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesNonNullableLists(
|
$this->checkHandlesNonNullableLists(
|
||||||
[ 1, 2 ],
|
[1, 2],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesNonNullableLists(
|
$this->checkHandlesNonNullableLists(
|
||||||
[ 1, null, 2 ],
|
[1, null, 2],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, null, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Returns null
|
// Returns null
|
||||||
$this->checkHandlesNonNullableLists(
|
$this->checkHandlesNonNullableLists(
|
||||||
null,
|
null,
|
||||||
[
|
[
|
||||||
'data' => [ 'nest' => null ],
|
'data' => ['nest' => null],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [['line' => 1, 'column' => 10]]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function checkHandlesNonNullableLists($testData, $expected, $debug = false)
|
||||||
|
{
|
||||||
|
$testType = Type::nonNull(Type::listOf(Type::int()));
|
||||||
|
$this->check($testType, $testData, $expected, $debug);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [T]!
|
* [T]!
|
||||||
*/
|
*/
|
||||||
@ -193,31 +239,31 @@ class ListsTest extends TestCase
|
|||||||
{
|
{
|
||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesNonNullableLists(
|
$this->checkHandlesNonNullableLists(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return [1,2];
|
return [1, 2];
|
||||||
}),
|
}),
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesNonNullableLists(
|
$this->checkHandlesNonNullableLists(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return [1, null, 2];
|
return [1, null, 2];
|
||||||
}),
|
}),
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, null, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Returns null
|
// Returns null
|
||||||
$this->checkHandlesNonNullableLists(
|
$this->checkHandlesNonNullableLists(
|
||||||
null,
|
null,
|
||||||
[
|
[
|
||||||
'data' => [ 'nest' => null ],
|
'data' => ['nest' => null],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [['line' => 1, 'column' => 10]]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -225,7 +271,7 @@ class ListsTest extends TestCase
|
|||||||
// Rejected
|
// Rejected
|
||||||
$this->checkHandlesNonNullableLists(
|
$this->checkHandlesNonNullableLists(
|
||||||
function () {
|
function () {
|
||||||
return new Deferred(function() {
|
return new Deferred(function () {
|
||||||
throw new UserError('bad');
|
throw new UserError('bad');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -235,9 +281,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test']
|
'path' => ['nest', 'test'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -250,45 +296,45 @@ class ListsTest extends TestCase
|
|||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesNonNullableLists(
|
$this->checkHandlesNonNullableLists(
|
||||||
[
|
[
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 1;
|
return 1;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesNonNullableLists(
|
$this->checkHandlesNonNullableLists(
|
||||||
[
|
[
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 1;
|
return 1;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, null, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains reject
|
// Contains reject
|
||||||
$this->checkHandlesNonNullableLists(
|
$this->checkHandlesNonNullableLists(
|
||||||
function () {
|
function () {
|
||||||
return [
|
return [
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 1;
|
return 1;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
throw new UserError('bad');
|
throw new UserError('bad');
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@ -297,9 +343,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test', 1]
|
'path' => ['nest', 'test', 1],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -311,21 +357,21 @@ class ListsTest extends TestCase
|
|||||||
{
|
{
|
||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesListOfNonNulls(
|
$this->checkHandlesListOfNonNulls(
|
||||||
[ 1, 2 ],
|
[1, 2],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesListOfNonNulls(
|
$this->checkHandlesListOfNonNulls(
|
||||||
[ 1, null, 2 ],
|
[1, null, 2],
|
||||||
[
|
[
|
||||||
'data' => [ 'nest' => [ 'test' => null ] ],
|
'data' => ['nest' => ['test' => null]],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [ ['line' => 1, 'column' => 10] ]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -333,10 +379,16 @@ class ListsTest extends TestCase
|
|||||||
// Returns null
|
// Returns null
|
||||||
$this->checkHandlesListOfNonNulls(
|
$this->checkHandlesListOfNonNulls(
|
||||||
null,
|
null,
|
||||||
[ 'data' => [ 'nest' => [ 'test' => null ] ] ]
|
['data' => ['nest' => ['test' => null]]]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function checkHandlesListOfNonNulls($testData, $expected, $debug = false)
|
||||||
|
{
|
||||||
|
$testType = Type::listOf(Type::nonNull(Type::int()));
|
||||||
|
$this->check($testType, $testData, $expected, $debug);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [T!]
|
* [T!]
|
||||||
*/
|
*/
|
||||||
@ -344,41 +396,41 @@ class ListsTest extends TestCase
|
|||||||
{
|
{
|
||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesListOfNonNulls(
|
$this->checkHandlesListOfNonNulls(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return [1, 2];
|
return [1, 2];
|
||||||
}),
|
}),
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesListOfNonNulls(
|
$this->checkHandlesListOfNonNulls(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return [1, null, 2];
|
return [1, null, 2];
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
'data' => [ 'nest' => [ 'test' => null ] ],
|
'data' => ['nest' => ['test' => null]],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [['line' => 1, 'column' => 10]]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
// Returns null
|
// Returns null
|
||||||
$this->checkHandlesListOfNonNulls(
|
$this->checkHandlesListOfNonNulls(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
[ 'data' => [ 'nest' => [ 'test' => null ] ] ]
|
['data' => ['nest' => ['test' => null]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Rejected
|
// Rejected
|
||||||
$this->checkHandlesListOfNonNulls(
|
$this->checkHandlesListOfNonNulls(
|
||||||
function () {
|
function () {
|
||||||
return new Deferred(function() {
|
return new Deferred(function () {
|
||||||
throw new UserError('bad');
|
throw new UserError('bad');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -388,9 +440,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test']
|
'path' => ['nest', 'test'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -403,39 +455,45 @@ class ListsTest extends TestCase
|
|||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesListOfNonNulls(
|
$this->checkHandlesListOfNonNulls(
|
||||||
[
|
[
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 1;
|
return 1;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesListOfNonNulls(
|
$this->checkHandlesListOfNonNulls(
|
||||||
[
|
[
|
||||||
new Deferred(function() {return 1;}),
|
new Deferred(function () {
|
||||||
new Deferred(function() {return null;}),
|
return 1;
|
||||||
new Deferred(function() {return 2;})
|
}),
|
||||||
|
new Deferred(function () {
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
new Deferred(function () {
|
||||||
|
return 2;
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => null ] ] ]
|
['data' => ['nest' => ['test' => null]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains reject
|
// Contains reject
|
||||||
$this->checkHandlesListOfNonNulls(
|
$this->checkHandlesListOfNonNulls(
|
||||||
function () {
|
function () {
|
||||||
return [
|
return [
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 1;
|
return 1;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
throw new UserError('bad');
|
throw new UserError('bad');
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@ -444,9 +502,9 @@ class ListsTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test', 1]
|
'path' => ['nest', 'test', 1],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -458,22 +516,21 @@ class ListsTest extends TestCase
|
|||||||
{
|
{
|
||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesNonNullListOfNonNulls(
|
$this->checkHandlesNonNullListOfNonNulls(
|
||||||
[ 1, 2 ],
|
[1, 2],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesNonNullListOfNonNulls(
|
$this->checkHandlesNonNullListOfNonNulls(
|
||||||
[ 1, null, 2 ],
|
[1, null, 2],
|
||||||
[
|
[
|
||||||
'data' => [ 'nest' => null ],
|
'data' => ['nest' => null],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [['line' => 1, 'column' => 10 ]]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -482,18 +539,24 @@ class ListsTest extends TestCase
|
|||||||
$this->checkHandlesNonNullListOfNonNulls(
|
$this->checkHandlesNonNullListOfNonNulls(
|
||||||
null,
|
null,
|
||||||
[
|
[
|
||||||
'data' => [ 'nest' => null ],
|
'data' => ['nest' => null],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [ ['line' => 1, 'column' => 10] ]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function checkHandlesNonNullListOfNonNulls($testData, $expected, $debug = false)
|
||||||
|
{
|
||||||
|
$testType = Type::nonNull(Type::listOf(Type::nonNull(Type::int())));
|
||||||
|
$this->check($testType, $testData, $expected, $debug);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [T!]!
|
* [T!]!
|
||||||
*/
|
*/
|
||||||
@ -501,42 +564,42 @@ class ListsTest extends TestCase
|
|||||||
{
|
{
|
||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesNonNullListOfNonNulls(
|
$this->checkHandlesNonNullListOfNonNulls(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return [1, 2];
|
return [1, 2];
|
||||||
}),
|
}),
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesNonNullListOfNonNulls(
|
$this->checkHandlesNonNullListOfNonNulls(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return [1, null, 2];
|
return [1, null, 2];
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
'data' => [ 'nest' => null ],
|
'data' => ['nest' => null],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [ ['line' => 1, 'column' => 10] ]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
// Returns null
|
// Returns null
|
||||||
$this->checkHandlesNonNullListOfNonNulls(
|
$this->checkHandlesNonNullListOfNonNulls(
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
'data' => [ 'nest' => null ],
|
'data' => ['nest' => null],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [ ['line' => 1, 'column' => 10] ]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -544,19 +607,19 @@ class ListsTest extends TestCase
|
|||||||
// Rejected
|
// Rejected
|
||||||
$this->checkHandlesNonNullListOfNonNulls(
|
$this->checkHandlesNonNullListOfNonNulls(
|
||||||
function () {
|
function () {
|
||||||
return new Deferred(function() {
|
return new Deferred(function () {
|
||||||
throw new UserError('bad');
|
throw new UserError('bad');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
'data' => ['nest' => null ],
|
'data' => ['nest' => null],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test']
|
'path' => ['nest', 'test'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -569,38 +632,38 @@ class ListsTest extends TestCase
|
|||||||
// Contains values
|
// Contains values
|
||||||
$this->checkHandlesNonNullListOfNonNulls(
|
$this->checkHandlesNonNullListOfNonNulls(
|
||||||
[
|
[
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 1;
|
return 1;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
|
|
||||||
],
|
],
|
||||||
[ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ]
|
['data' => ['nest' => ['test' => [1, 2]]]]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Contains null
|
// Contains null
|
||||||
$this->checkHandlesNonNullListOfNonNulls(
|
$this->checkHandlesNonNullListOfNonNulls(
|
||||||
[
|
[
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 1;
|
return 1;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'data' => [ 'nest' => null ],
|
'data' => ['nest' => null],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.test.',
|
||||||
'locations' => [['line' => 1, 'column' => 10]]
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -609,83 +672,27 @@ class ListsTest extends TestCase
|
|||||||
$this->checkHandlesNonNullListOfNonNulls(
|
$this->checkHandlesNonNullListOfNonNulls(
|
||||||
function () {
|
function () {
|
||||||
return [
|
return [
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 1;
|
return 1;
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
throw new UserError('bad');
|
throw new UserError('bad');
|
||||||
}),
|
}),
|
||||||
new Deferred(function() {
|
new Deferred(function () {
|
||||||
return 2;
|
return 2;
|
||||||
})
|
}),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
'data' => ['nest' => null ],
|
'data' => ['nest' => null],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' => 'bad',
|
'message' => 'bad',
|
||||||
'locations' => [['line' => 1, 'column' => 10]],
|
'locations' => [['line' => 1, 'column' => 10]],
|
||||||
'path' => ['nest', 'test']
|
'path' => ['nest', 'test'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkHandlesNullableLists($testData, $expected)
|
|
||||||
{
|
|
||||||
$testType = Type::listOf(Type::int());
|
|
||||||
$this->check($testType, $testData, $expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function checkHandlesNonNullableLists($testData, $expected, $debug = false)
|
|
||||||
{
|
|
||||||
$testType = Type::nonNull(Type::listOf(Type::int()));
|
|
||||||
$this->check($testType, $testData, $expected, $debug);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function checkHandlesListOfNonNulls($testData, $expected, $debug = false)
|
|
||||||
{
|
|
||||||
$testType = Type::listOf(Type::nonNull(Type::int()));
|
|
||||||
$this->check($testType, $testData, $expected, $debug);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function checkHandlesNonNullListOfNonNulls($testData, $expected, $debug = false)
|
|
||||||
{
|
|
||||||
$testType = Type::nonNull(Type::listOf(Type::nonNull(Type::int())));
|
|
||||||
$this->check($testType, $testData, $expected, $debug);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function check($testType, $testData, $expected, $debug = false)
|
|
||||||
{
|
|
||||||
$data = ['test' => $testData];
|
|
||||||
$dataType = null;
|
|
||||||
|
|
||||||
$dataType = new ObjectType([
|
|
||||||
'name' => 'DataType',
|
|
||||||
'fields' => function () use (&$testType, &$dataType, $data) {
|
|
||||||
return [
|
|
||||||
'test' => [
|
|
||||||
'type' => $testType
|
|
||||||
],
|
|
||||||
'nest' => [
|
|
||||||
'type' => $dataType,
|
|
||||||
'resolve' => function () use ($data) {
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
$schema = new Schema([
|
|
||||||
'query' => $dataType
|
|
||||||
]);
|
|
||||||
|
|
||||||
$ast = Parser::parse('{ nest { test } }');
|
|
||||||
|
|
||||||
$result = Executor::execute($schema, $ast, $data);
|
|
||||||
$this->assertArraySubset($expected, $result->toArray($debug));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
|
||||||
use GraphQL\Executor\ExecutionResult;
|
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Error\FormattedError;
|
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\SourceLocation;
|
use GraphQL\Tests\Executor\TestClasses\Root;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class MutationsTest extends TestCase
|
class MutationsTest extends TestCase
|
||||||
{
|
{
|
||||||
// Execute: Handles mutation execution ordering
|
// Execute: Handles mutation execution ordering
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('evaluates mutations serially')
|
* @see it('evaluates mutations serially')
|
||||||
*/
|
*/
|
||||||
@ -42,26 +41,69 @@ class MutationsTest extends TestCase
|
|||||||
$mutationResult = Executor::execute($this->schema(), $ast, new Root(6));
|
$mutationResult = Executor::execute($this->schema(), $ast, new Root(6));
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'first' => [
|
'first' => ['theNumber' => 1],
|
||||||
'theNumber' => 1
|
'second' => ['theNumber' => 2],
|
||||||
|
'third' => ['theNumber' => 3],
|
||||||
|
'fourth' => ['theNumber' => 4],
|
||||||
|
'fifth' => ['theNumber' => 5],
|
||||||
],
|
],
|
||||||
'second' => [
|
|
||||||
'theNumber' => 2
|
|
||||||
],
|
|
||||||
'third' => [
|
|
||||||
'theNumber' => 3
|
|
||||||
],
|
|
||||||
'fourth' => [
|
|
||||||
'theNumber' => 4
|
|
||||||
],
|
|
||||||
'fifth' => [
|
|
||||||
'theNumber' => 5
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $mutationResult->toArray());
|
$this->assertEquals($expected, $mutationResult->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function schema() : Schema
|
||||||
|
{
|
||||||
|
$numberHolderType = new ObjectType([
|
||||||
|
'fields' => [
|
||||||
|
'theNumber' => ['type' => Type::int()],
|
||||||
|
],
|
||||||
|
'name' => 'NumberHolder',
|
||||||
|
]);
|
||||||
|
$schema = new Schema([
|
||||||
|
'query' => new ObjectType([
|
||||||
|
'fields' => [
|
||||||
|
'numberHolder' => ['type' => $numberHolderType],
|
||||||
|
],
|
||||||
|
'name' => 'Query',
|
||||||
|
]),
|
||||||
|
'mutation' => new ObjectType([
|
||||||
|
'fields' => [
|
||||||
|
'immediatelyChangeTheNumber' => [
|
||||||
|
'type' => $numberHolderType,
|
||||||
|
'args' => ['newNumber' => ['type' => Type::int()]],
|
||||||
|
'resolve' => function (Root $obj, $args) {
|
||||||
|
return $obj->immediatelyChangeTheNumber($args['newNumber']);
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'promiseToChangeTheNumber' => [
|
||||||
|
'type' => $numberHolderType,
|
||||||
|
'args' => ['newNumber' => ['type' => Type::int()]],
|
||||||
|
'resolve' => function (Root $obj, $args) {
|
||||||
|
return $obj->promiseToChangeTheNumber($args['newNumber']);
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'failToChangeTheNumber' => [
|
||||||
|
'type' => $numberHolderType,
|
||||||
|
'args' => ['newNumber' => ['type' => Type::int()]],
|
||||||
|
'resolve' => function (Root $obj, $args) {
|
||||||
|
$obj->failToChangeTheNumber();
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'promiseAndFailToChangeTheNumber' => [
|
||||||
|
'type' => $numberHolderType,
|
||||||
|
'args' => ['newNumber' => ['type' => Type::int()]],
|
||||||
|
'resolve' => function (Root $obj, $args) {
|
||||||
|
return $obj->promiseAndFailToChangeTheNumber();
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'name' => 'Mutation',
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $schema;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('evaluates mutations correctly in the presense of a failed mutation')
|
* @see it('evaluates mutations correctly in the presense of a failed mutation')
|
||||||
*/
|
*/
|
||||||
@ -91,143 +133,24 @@ class MutationsTest extends TestCase
|
|||||||
$mutationResult = Executor::execute($this->schema(), $ast, new Root(6));
|
$mutationResult = Executor::execute($this->schema(), $ast, new Root(6));
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'first' => [
|
'first' => ['theNumber' => 1],
|
||||||
'theNumber' => 1
|
'second' => ['theNumber' => 2],
|
||||||
],
|
|
||||||
'second' => [
|
|
||||||
'theNumber' => 2
|
|
||||||
],
|
|
||||||
'third' => null,
|
'third' => null,
|
||||||
'fourth' => [
|
'fourth' => ['theNumber' => 4],
|
||||||
'theNumber' => 4
|
'fifth' => ['theNumber' => 5],
|
||||||
],
|
|
||||||
'fifth' => [
|
|
||||||
'theNumber' => 5
|
|
||||||
],
|
|
||||||
'sixth' => null,
|
'sixth' => null,
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot change the number',
|
'debugMessage' => 'Cannot change the number',
|
||||||
'locations' => [['line' => 8, 'column' => 7]]
|
'locations' => [['line' => 8, 'column' => 7]],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot change the number',
|
'debugMessage' => 'Cannot change the number',
|
||||||
'locations' => [['line' => 17, 'column' => 7]]
|
'locations' => [['line' => 17, 'column' => 7]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, $mutationResult->toArray(true));
|
$this->assertArraySubset($expected, $mutationResult->toArray(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function schema()
|
|
||||||
{
|
|
||||||
$numberHolderType = new ObjectType([
|
|
||||||
'fields' => [
|
|
||||||
'theNumber' => ['type' => Type::int()],
|
|
||||||
],
|
|
||||||
'name' => 'NumberHolder',
|
|
||||||
]);
|
|
||||||
$schema = new Schema([
|
|
||||||
'query' => new ObjectType([
|
|
||||||
'fields' => [
|
|
||||||
'numberHolder' => ['type' => $numberHolderType],
|
|
||||||
],
|
|
||||||
'name' => 'Query',
|
|
||||||
]),
|
|
||||||
'mutation' => new ObjectType([
|
|
||||||
'fields' => [
|
|
||||||
'immediatelyChangeTheNumber' => [
|
|
||||||
'type' => $numberHolderType,
|
|
||||||
'args' => ['newNumber' => ['type' => Type::int()]],
|
|
||||||
'resolve' => (function (Root $obj, $args) {
|
|
||||||
return $obj->immediatelyChangeTheNumber($args['newNumber']);
|
|
||||||
})
|
|
||||||
],
|
|
||||||
'promiseToChangeTheNumber' => [
|
|
||||||
'type' => $numberHolderType,
|
|
||||||
'args' => ['newNumber' => ['type' => Type::int()]],
|
|
||||||
'resolve' => (function (Root $obj, $args) {
|
|
||||||
return $obj->promiseToChangeTheNumber($args['newNumber']);
|
|
||||||
})
|
|
||||||
],
|
|
||||||
'failToChangeTheNumber' => [
|
|
||||||
'type' => $numberHolderType,
|
|
||||||
'args' => ['newNumber' => ['type' => Type::int()]],
|
|
||||||
'resolve' => (function (Root $obj, $args) {
|
|
||||||
return $obj->failToChangeTheNumber($args['newNumber']);
|
|
||||||
})
|
|
||||||
],
|
|
||||||
'promiseAndFailToChangeTheNumber' => [
|
|
||||||
'type' => $numberHolderType,
|
|
||||||
'args' => ['newNumber' => ['type' => Type::int()]],
|
|
||||||
'resolve' => (function (Root $obj, $args) {
|
|
||||||
return $obj->promiseAndFailToChangeTheNumber($args['newNumber']);
|
|
||||||
})
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'name' => 'Mutation',
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NumberHolder
|
|
||||||
{
|
|
||||||
public $theNumber;
|
|
||||||
|
|
||||||
public function __construct($originalNumber)
|
|
||||||
{
|
|
||||||
$this->theNumber = $originalNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Root {
|
|
||||||
public $numberHolder;
|
|
||||||
|
|
||||||
public function __construct($originalNumber)
|
|
||||||
{
|
|
||||||
$this->numberHolder = new NumberHolder($originalNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $newNumber
|
|
||||||
* @return NumberHolder
|
|
||||||
*/
|
|
||||||
public function immediatelyChangeTheNumber($newNumber)
|
|
||||||
{
|
|
||||||
$this->numberHolder->theNumber = $newNumber;
|
|
||||||
return $this->numberHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $newNumber
|
|
||||||
*
|
|
||||||
* @return Deferred
|
|
||||||
*/
|
|
||||||
public function promiseToChangeTheNumber($newNumber)
|
|
||||||
{
|
|
||||||
return new Deferred(function () use ($newNumber) {
|
|
||||||
return $this->immediatelyChangeTheNumber($newNumber);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function failToChangeTheNumber()
|
|
||||||
{
|
|
||||||
throw new \Exception('Cannot change the number');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Deferred
|
|
||||||
*/
|
|
||||||
public function promiseAndFailToChangeTheNumber()
|
|
||||||
{
|
|
||||||
return new Deferred(function () {
|
|
||||||
throw new \Exception("Cannot change the number");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
|
use GraphQL\Error\FormattedError;
|
||||||
use GraphQL\Error\UserError;
|
use GraphQL\Error\UserError;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Error\FormattedError;
|
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\SourceLocation;
|
use GraphQL\Language\SourceLocation;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class NonNullTest extends TestCase
|
class NonNullTest extends TestCase
|
||||||
@ -27,8 +29,13 @@ class NonNullTest extends TestCase
|
|||||||
/** @var \Exception */
|
/** @var \Exception */
|
||||||
public $promiseNonNullError;
|
public $promiseNonNullError;
|
||||||
|
|
||||||
|
/** @var callable[] */
|
||||||
public $throwingData;
|
public $throwingData;
|
||||||
|
|
||||||
|
/** @var callable[] */
|
||||||
public $nullingData;
|
public $nullingData;
|
||||||
|
|
||||||
|
/** @var Schema */
|
||||||
public $schema;
|
public $schema;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -110,7 +117,7 @@ class NonNullTest extends TestCase
|
|||||||
|
|
||||||
$dataType = new ObjectType([
|
$dataType = new ObjectType([
|
||||||
'name' => 'DataType',
|
'name' => 'DataType',
|
||||||
'fields' => function() use (&$dataType) {
|
'fields' => function () use (&$dataType) {
|
||||||
return [
|
return [
|
||||||
'sync' => ['type' => Type::string()],
|
'sync' => ['type' => Type::string()],
|
||||||
'syncNonNull' => ['type' => Type::nonNull(Type::string())],
|
'syncNonNull' => ['type' => Type::nonNull(Type::string())],
|
||||||
@ -121,7 +128,7 @@ class NonNullTest extends TestCase
|
|||||||
'promiseNest' => $dataType,
|
'promiseNest' => $dataType,
|
||||||
'promiseNonNullNest' => Type::nonNull($dataType),
|
'promiseNonNullNest' => Type::nonNull($dataType),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->schema = new Schema(['query' => $dataType]);
|
$this->schema = new Schema(['query' => $dataType]);
|
||||||
@ -143,17 +150,18 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['sync' => null],
|
||||||
'sync' => null,
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create(
|
FormattedError::create(
|
||||||
$this->syncError->getMessage(),
|
$this->syncError->getMessage(),
|
||||||
[new SourceLocation(3, 9)]
|
[new SourceLocation(3, 9)]
|
||||||
)
|
),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsANullableFieldThatThrowsInAPromise() : void
|
public function testNullsANullableFieldThatThrowsInAPromise() : void
|
||||||
@ -167,18 +175,19 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promise' => null],
|
||||||
'promise' => null,
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create(
|
FormattedError::create(
|
||||||
$this->promiseError->getMessage(),
|
$this->promiseError->getMessage(),
|
||||||
[new SourceLocation(3, 9)]
|
[new SourceLocation(3, 9)]
|
||||||
)
|
),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatThrowsSynchronously() : void
|
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatThrowsSynchronously() : void
|
||||||
@ -195,14 +204,15 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['syncNest' => null],
|
||||||
'syncNest' => null
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(4, 11)])
|
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(4, 11)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsAsynchronouslyReturnedObjectThatContainsANonNullableFieldThatThrowsInAPromise() : void
|
public function testNullsAsynchronouslyReturnedObjectThatContainsANonNullableFieldThatThrowsInAPromise() : void
|
||||||
@ -218,15 +228,16 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['syncNest' => null],
|
||||||
'syncNest' => null
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(4, 11)])
|
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(4, 11)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsAnObjectReturnedInAPromiseThatContainsANonNullableFieldThatThrowsSynchronously() : void
|
public function testNullsAnObjectReturnedInAPromiseThatContainsANonNullableFieldThatThrowsSynchronously() : void
|
||||||
@ -242,15 +253,16 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promiseNest' => null],
|
||||||
'promiseNest' => null
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(4, 11)])
|
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(4, 11)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsAnObjectReturnedInAPromiseThatContainsANonNullableFieldThatThrowsInAPromise() : void
|
public function testNullsAnObjectReturnedInAPromiseThatContainsANonNullableFieldThatThrowsInAPromise() : void
|
||||||
@ -266,15 +278,16 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promiseNest' => null],
|
||||||
'promiseNest' => null
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(4, 11)])
|
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(4, 11)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -353,10 +366,13 @@ class NonNullTest extends TestCase
|
|||||||
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(17, 11)]),
|
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(17, 11)]),
|
||||||
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(20, 13)]),
|
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(20, 13)]),
|
||||||
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(24, 13)]),
|
FormattedError::create($this->promiseError->getMessage(), [new SourceLocation(24, 13)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsTheFirstNullableObjectAfterAFieldThrowsInALongChainOfFieldsThatAreNonNull() : void
|
public function testNullsTheFirstNullableObjectAfterAFieldThrowsInALongChainOfFieldsThatAreNonNull() : void
|
||||||
@ -424,10 +440,13 @@ class NonNullTest extends TestCase
|
|||||||
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(19, 19)]),
|
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(19, 19)]),
|
||||||
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(30, 19)]),
|
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(30, 19)]),
|
||||||
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(41, 19)]),
|
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(41, 19)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsANullableFieldThatSynchronouslyReturnsNull() : void
|
public function testNullsANullableFieldThatSynchronouslyReturnsNull() : void
|
||||||
@ -441,11 +460,12 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['sync' => null],
|
||||||
'sync' => null,
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray());
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsANullableFieldThatReturnsNullInAPromise() : void
|
public function testNullsANullableFieldThatReturnsNullInAPromise() : void
|
||||||
@ -459,12 +479,13 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promise' => null],
|
||||||
'promise' => null,
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatReturnsNullSynchronously() : void
|
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatReturnsNullSynchronously() : void
|
||||||
@ -480,17 +501,18 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['syncNest' => null],
|
||||||
'syncNest' => null
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
||||||
'locations' => [['line' => 4, 'column' => 11]]
|
'locations' => [['line' => 4, 'column' => 11]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray(true));
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray(true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatReturnsNullInAPromise() : void
|
public function testNullsASynchronouslyReturnedObjectThatContainsANonNullableFieldThatReturnsNullInAPromise() : void
|
||||||
@ -506,15 +528,13 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['syncNest' => null],
|
||||||
'syncNest' => null,
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
||||||
'locations' => [['line' => 4, 'column' => 11]]
|
'locations' => [['line' => 4, 'column' => 11]],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
@ -536,15 +556,13 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promiseNest' => null],
|
||||||
'promiseNest' => null,
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
||||||
'locations' => [['line' => 4, 'column' => 11]]
|
'locations' => [['line' => 4, 'column' => 11]],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
@ -566,15 +584,13 @@ class NonNullTest extends TestCase
|
|||||||
$ast = Parser::parse($doc);
|
$ast = Parser::parse($doc);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['promiseNest' => null],
|
||||||
'promiseNest' => null,
|
|
||||||
],
|
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
||||||
'locations' => [['line' => 4, 'column' => 11]]
|
'locations' => [['line' => 4, 'column' => 11]],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
@ -628,7 +644,7 @@ class NonNullTest extends TestCase
|
|||||||
'promiseNest' => [
|
'promiseNest' => [
|
||||||
'sync' => null,
|
'sync' => null,
|
||||||
'promise' => null,
|
'promise' => null,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'promiseNest' => [
|
'promiseNest' => [
|
||||||
'sync' => null,
|
'sync' => null,
|
||||||
@ -640,9 +656,9 @@ class NonNullTest extends TestCase
|
|||||||
'promiseNest' => [
|
'promiseNest' => [
|
||||||
'sync' => null,
|
'sync' => null,
|
||||||
'promise' => null,
|
'promise' => null,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$actual = Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray();
|
$actual = Executor::execute($this->schema, $ast, $this->nullingData, null, [], 'Q')->toArray();
|
||||||
@ -710,11 +726,11 @@ class NonNullTest extends TestCase
|
|||||||
'anotherPromiseNest' => null,
|
'anotherPromiseNest' => null,
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
['debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.', 'locations' => [ ['line' => 8, 'column' => 19]]],
|
['debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.', 'locations' => [['line' => 8, 'column' => 19]]],
|
||||||
['debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.', 'locations' => [ ['line' => 19, 'column' => 19]]],
|
['debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.', 'locations' => [['line' => 19, 'column' => 19]]],
|
||||||
['debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.', 'locations' => [ ['line' => 30, 'column' => 19]]],
|
['debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.', 'locations' => [['line' => 30, 'column' => 19]]],
|
||||||
['debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.', 'locations' => [ ['line' => 41, 'column' => 19]]],
|
['debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.', 'locations' => [['line' => 41, 'column' => 19]]],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
@ -734,8 +750,8 @@ class NonNullTest extends TestCase
|
|||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(2, 17)])
|
FormattedError::create($this->syncNonNullError->getMessage(), [new SourceLocation(2, 17)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$actual = Executor::execute($this->schema, Parser::parse($doc), $this->throwingData)->toArray();
|
$actual = Executor::execute($this->schema, Parser::parse($doc), $this->throwingData)->toArray();
|
||||||
$this->assertArraySubset($expected, $actual);
|
$this->assertArraySubset($expected, $actual);
|
||||||
@ -752,10 +768,13 @@ class NonNullTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(2, 17)]),
|
FormattedError::create($this->promiseNonNullError->getMessage(), [new SourceLocation(2, 17)]),
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray());
|
$this->assertArraySubset(
|
||||||
|
$expected,
|
||||||
|
Executor::execute($this->schema, $ast, $this->throwingData, null, [], 'Q')->toArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNullsTheTopLevelIfSyncNonNullableFieldReturnsNull() : void
|
public function testNullsTheTopLevelIfSyncNonNullableFieldReturnsNull() : void
|
||||||
@ -769,9 +788,9 @@ class NonNullTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.syncNonNull.',
|
||||||
'locations' => [['line' => 2, 'column' => 17]]
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
$expected,
|
$expected,
|
||||||
@ -791,9 +810,9 @@ class NonNullTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
'debugMessage' => 'Cannot return null for non-nullable field DataType.promiseNonNull.',
|
||||||
'locations' => [['line' => 2, 'column' => 17]]
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset(
|
$this->assertArraySubset(
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor\Promise;
|
namespace GraphQL\Tests\Executor\Promise;
|
||||||
|
|
||||||
|
|
||||||
use GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter;
|
use GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter;
|
||||||
use GraphQL\Executor\Promise\Promise;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use React\Promise\Deferred;
|
use React\Promise\Deferred;
|
||||||
use React\Promise\FulfilledPromise;
|
use React\Promise\FulfilledPromise;
|
||||||
use React\Promise\LazyPromise;
|
use React\Promise\LazyPromise;
|
||||||
use React\Promise\Promise as ReactPromise;
|
use React\Promise\Promise as ReactPromise;
|
||||||
use React\Promise\RejectedPromise;
|
use React\Promise\RejectedPromise;
|
||||||
|
use function class_exists;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group ReactPromise
|
* @group ReactPromise
|
||||||
@ -20,27 +20,35 @@ class ReactPromiseAdapterTest extends TestCase
|
|||||||
{
|
{
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
if(! class_exists('React\Promise\Promise')) {
|
if (class_exists('React\Promise\Promise')) {
|
||||||
$this->markTestSkipped('react/promise package must be installed to run GraphQL\Tests\Executor\Promise\ReactPromiseAdapterTest');
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->markTestSkipped('react/promise package must be installed to run GraphQL\Tests\Executor\Promise\ReactPromiseAdapterTest');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsThenableReturnsTrueWhenAReactPromiseIsGiven() : void
|
public function testIsThenableReturnsTrueWhenAReactPromiseIsGiven() : void
|
||||||
{
|
{
|
||||||
$reactAdapter = new ReactPromiseAdapter();
|
$reactAdapter = new ReactPromiseAdapter();
|
||||||
|
|
||||||
$this->assertSame(true, $reactAdapter->isThenable(new ReactPromise(function() {})));
|
$this->assertTrue(
|
||||||
$this->assertSame(true, $reactAdapter->isThenable(new FulfilledPromise()));
|
$reactAdapter->isThenable(new ReactPromise(function () {
|
||||||
$this->assertSame(true, $reactAdapter->isThenable(new RejectedPromise()));
|
}))
|
||||||
$this->assertSame(true, $reactAdapter->isThenable(new LazyPromise(function() {})));
|
);
|
||||||
$this->assertSame(false, $reactAdapter->isThenable(false));
|
$this->assertTrue($reactAdapter->isThenable(new FulfilledPromise()));
|
||||||
$this->assertSame(false, $reactAdapter->isThenable(true));
|
$this->assertTrue($reactAdapter->isThenable(new RejectedPromise()));
|
||||||
$this->assertSame(false, $reactAdapter->isThenable(1));
|
$this->assertTrue(
|
||||||
$this->assertSame(false, $reactAdapter->isThenable(0));
|
$reactAdapter->isThenable(new LazyPromise(function () {
|
||||||
$this->assertSame(false, $reactAdapter->isThenable('test'));
|
}))
|
||||||
$this->assertSame(false, $reactAdapter->isThenable(''));
|
);
|
||||||
$this->assertSame(false, $reactAdapter->isThenable([]));
|
$this->assertFalse($reactAdapter->isThenable(false));
|
||||||
$this->assertSame(false, $reactAdapter->isThenable(new \stdClass()));
|
$this->assertFalse($reactAdapter->isThenable(true));
|
||||||
|
$this->assertFalse($reactAdapter->isThenable(1));
|
||||||
|
$this->assertFalse($reactAdapter->isThenable(0));
|
||||||
|
$this->assertFalse($reactAdapter->isThenable('test'));
|
||||||
|
$this->assertFalse($reactAdapter->isThenable(''));
|
||||||
|
$this->assertFalse($reactAdapter->isThenable([]));
|
||||||
|
$this->assertFalse($reactAdapter->isThenable(new \stdClass()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testConvertsReactPromisesToGraphQlOnes() : void
|
public function testConvertsReactPromisesToGraphQlOnes() : void
|
||||||
@ -62,9 +70,12 @@ class ReactPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
$result = null;
|
$result = null;
|
||||||
|
|
||||||
$resultPromise = $reactAdapter->then($promise, function ($value) use (&$result) {
|
$resultPromise = $reactAdapter->then(
|
||||||
|
$promise,
|
||||||
|
function ($value) use (&$result) {
|
||||||
$result = $value;
|
$result = $value;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertSame(1, $result);
|
$this->assertSame(1, $result);
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $resultPromise);
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $resultPromise);
|
||||||
@ -117,9 +128,12 @@ class ReactPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
$exception = null;
|
$exception = null;
|
||||||
|
|
||||||
$rejectedPromise->then(null, function ($error) use (&$exception) {
|
$rejectedPromise->then(
|
||||||
|
null,
|
||||||
|
function ($error) use (&$exception) {
|
||||||
$exception = $error;
|
$exception = $error;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf('\Exception', $exception);
|
$this->assertInstanceOf('\Exception', $exception);
|
||||||
$this->assertEquals('I am a bad promise', $exception->getMessage());
|
$this->assertEquals('I am a bad promise', $exception->getMessage());
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor\Promise;
|
namespace GraphQL\Tests\Executor\Promise;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
@ -10,9 +13,7 @@ use PHPUnit\Framework\TestCase;
|
|||||||
|
|
||||||
class SyncPromiseAdapterTest extends TestCase
|
class SyncPromiseAdapterTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var SyncPromiseAdapter */
|
||||||
* @var SyncPromiseAdapter
|
|
||||||
*/
|
|
||||||
private $promises;
|
private $promises;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -22,7 +23,11 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
public function testIsThenable() : void
|
public function testIsThenable() : void
|
||||||
{
|
{
|
||||||
$this->assertEquals(true, $this->promises->isThenable(new Deferred(function() {})));
|
$this->assertEquals(
|
||||||
|
true,
|
||||||
|
$this->promises->isThenable(new Deferred(function () {
|
||||||
|
}))
|
||||||
|
);
|
||||||
$this->assertEquals(false, $this->promises->isThenable(false));
|
$this->assertEquals(false, $this->promises->isThenable(false));
|
||||||
$this->assertEquals(false, $this->promises->isThenable(true));
|
$this->assertEquals(false, $this->promises->isThenable(true));
|
||||||
$this->assertEquals(false, $this->promises->isThenable(1));
|
$this->assertEquals(false, $this->promises->isThenable(1));
|
||||||
@ -35,7 +40,8 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
public function testConvert() : void
|
public function testConvert() : void
|
||||||
{
|
{
|
||||||
$dfd = new Deferred(function() {});
|
$dfd = new Deferred(function () {
|
||||||
|
});
|
||||||
$result = $this->promises->convertThenable($dfd);
|
$result = $this->promises->convertThenable($dfd);
|
||||||
|
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $result);
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $result);
|
||||||
@ -48,7 +54,8 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
public function testThen() : void
|
public function testThen() : void
|
||||||
{
|
{
|
||||||
$dfd = new Deferred(function() {});
|
$dfd = new Deferred(function () {
|
||||||
|
});
|
||||||
$promise = $this->promises->convertThenable($dfd);
|
$promise = $this->promises->convertThenable($dfd);
|
||||||
|
|
||||||
$result = $this->promises->then($promise);
|
$result = $this->promises->then($promise);
|
||||||
@ -59,18 +66,55 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
|
|
||||||
public function testCreatePromise() : void
|
public function testCreatePromise() : void
|
||||||
{
|
{
|
||||||
$promise = $this->promises->create(function($resolve, $reject) {});
|
$promise = $this->promises->create(function ($resolve, $reject) {
|
||||||
|
});
|
||||||
|
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $promise);
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $promise);
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Adapter\SyncPromise', $promise->adoptedPromise);
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Adapter\SyncPromise', $promise->adoptedPromise);
|
||||||
|
|
||||||
$promise = $this->promises->create(function($resolve, $reject) {
|
$promise = $this->promises->create(function ($resolve, $reject) {
|
||||||
$resolve('A');
|
$resolve('A');
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->assertValidPromise($promise, null, 'A', SyncPromise::FULFILLED);
|
$this->assertValidPromise($promise, null, 'A', SyncPromise::FULFILLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function assertValidPromise($promise, $expectedNextReason, $expectedNextValue, $expectedNextState)
|
||||||
|
{
|
||||||
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $promise);
|
||||||
|
$this->assertInstanceOf('GraphQL\Executor\Promise\Adapter\SyncPromise', $promise->adoptedPromise);
|
||||||
|
|
||||||
|
$actualNextValue = null;
|
||||||
|
$actualNextReason = null;
|
||||||
|
$onFulfilledCalled = false;
|
||||||
|
$onRejectedCalled = false;
|
||||||
|
|
||||||
|
$promise->then(
|
||||||
|
function ($nextValue) use (&$actualNextValue, &$onFulfilledCalled) {
|
||||||
|
$onFulfilledCalled = true;
|
||||||
|
$actualNextValue = $nextValue;
|
||||||
|
},
|
||||||
|
function (\Throwable $reason) use (&$actualNextReason, &$onRejectedCalled) {
|
||||||
|
$onRejectedCalled = true;
|
||||||
|
$actualNextReason = $reason->getMessage();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame($onFulfilledCalled, false);
|
||||||
|
$this->assertSame($onRejectedCalled, false);
|
||||||
|
|
||||||
|
SyncPromise::runQueue();
|
||||||
|
|
||||||
|
if ($expectedNextState !== SyncPromise::PENDING) {
|
||||||
|
$this->assertSame(! $expectedNextReason, $onFulfilledCalled);
|
||||||
|
$this->assertSame(! ! $expectedNextReason, $onRejectedCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertSame($expectedNextValue, $actualNextValue);
|
||||||
|
$this->assertSame($expectedNextReason, $actualNextReason);
|
||||||
|
$this->assertSame($expectedNextState, $promise->adoptedPromise->state);
|
||||||
|
}
|
||||||
|
|
||||||
public function testCreateFulfilledPromise() : void
|
public function testCreateFulfilledPromise() : void
|
||||||
{
|
{
|
||||||
$promise = $this->promises->createFulfilled('test');
|
$promise = $this->promises->createFulfilled('test');
|
||||||
@ -94,8 +138,8 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
$promise1 = new SyncPromise();
|
$promise1 = new SyncPromise();
|
||||||
$promise2 = new SyncPromise();
|
$promise2 = new SyncPromise();
|
||||||
$promise3 = $promise2->then(
|
$promise3 = $promise2->then(
|
||||||
function($value) {
|
function ($value) {
|
||||||
return $value .'-value3';
|
return $value . '-value3';
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -105,7 +149,7 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
new Promise($promise2, $this->promises),
|
new Promise($promise2, $this->promises),
|
||||||
3,
|
3,
|
||||||
new Promise($promise3, $this->promises),
|
new Promise($promise3, $this->promises),
|
||||||
[]
|
[],
|
||||||
];
|
];
|
||||||
|
|
||||||
$promise = $this->promises->all($data);
|
$promise = $this->promises->all($data);
|
||||||
@ -114,36 +158,46 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
$promise1->resolve('value1');
|
$promise1->resolve('value1');
|
||||||
$this->assertValidPromise($promise, null, null, SyncPromise::PENDING);
|
$this->assertValidPromise($promise, null, null, SyncPromise::PENDING);
|
||||||
$promise2->resolve('value2');
|
$promise2->resolve('value2');
|
||||||
$this->assertValidPromise($promise, null, ['1', 'value1', 'value2', 3, 'value2-value3', []], SyncPromise::FULFILLED);
|
$this->assertValidPromise(
|
||||||
|
$promise,
|
||||||
|
null,
|
||||||
|
['1', 'value1', 'value2', 3, 'value2-value3', []],
|
||||||
|
SyncPromise::FULFILLED
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testWait() : void
|
public function testWait() : void
|
||||||
{
|
{
|
||||||
$called = [];
|
$called = [];
|
||||||
|
|
||||||
$deferred1 = new Deferred(function() use (&$called) {
|
$deferred1 = new Deferred(function () use (&$called) {
|
||||||
$called[] = 1;
|
$called[] = 1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
});
|
});
|
||||||
$deferred2 = new Deferred(function() use (&$called) {
|
$deferred2 = new Deferred(function () use (&$called) {
|
||||||
$called[] = 2;
|
$called[] = 2;
|
||||||
|
|
||||||
return 2;
|
return 2;
|
||||||
});
|
});
|
||||||
|
|
||||||
$p1 = $this->promises->convertThenable($deferred1);
|
$p1 = $this->promises->convertThenable($deferred1);
|
||||||
$p2 = $this->promises->convertThenable($deferred2);
|
$p2 = $this->promises->convertThenable($deferred2);
|
||||||
|
|
||||||
$p3 = $p2->then(function() use (&$called) {
|
$p3 = $p2->then(function () use (&$called) {
|
||||||
$dfd = new Deferred(function() use (&$called) {
|
$dfd = new Deferred(function () use (&$called) {
|
||||||
$called[] = 3;
|
$called[] = 3;
|
||||||
|
|
||||||
return 3;
|
return 3;
|
||||||
});
|
});
|
||||||
|
|
||||||
return $this->promises->convertThenable($dfd);
|
return $this->promises->convertThenable($dfd);
|
||||||
});
|
});
|
||||||
|
|
||||||
$p4 = $p3->then(function() use (&$called) {
|
$p4 = $p3->then(function () use (&$called) {
|
||||||
return new Deferred(function() use (&$called) {
|
return new Deferred(function () use (&$called) {
|
||||||
$called[] = 4;
|
$called[] = 4;
|
||||||
|
|
||||||
return 4;
|
return 4;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -156,46 +210,10 @@ class SyncPromiseAdapterTest extends TestCase
|
|||||||
$this->assertEquals(SyncPromise::PENDING, $all->adoptedPromise->state);
|
$this->assertEquals(SyncPromise::PENDING, $all->adoptedPromise->state);
|
||||||
$this->assertEquals([1, 2], $called);
|
$this->assertEquals([1, 2], $called);
|
||||||
|
|
||||||
$expectedResult = [0,1,2,3,4];
|
$expectedResult = [0, 1, 2, 3, 4];
|
||||||
$result = $this->promises->wait($all);
|
$result = $this->promises->wait($all);
|
||||||
$this->assertEquals($expectedResult, $result);
|
$this->assertEquals($expectedResult, $result);
|
||||||
$this->assertEquals([1, 2, 3, 4], $called);
|
$this->assertEquals([1, 2, 3, 4], $called);
|
||||||
$this->assertValidPromise($all, null, [0,1,2,3,4], SyncPromise::FULFILLED);
|
$this->assertValidPromise($all, null, [0, 1, 2, 3, 4], SyncPromise::FULFILLED);
|
||||||
}
|
|
||||||
|
|
||||||
private function assertValidPromise($promise, $expectedNextReason, $expectedNextValue, $expectedNextState)
|
|
||||||
{
|
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $promise);
|
|
||||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Adapter\SyncPromise', $promise->adoptedPromise);
|
|
||||||
|
|
||||||
$actualNextValue = null;
|
|
||||||
$actualNextReason = null;
|
|
||||||
$onFulfilledCalled = false;
|
|
||||||
$onRejectedCalled = false;
|
|
||||||
|
|
||||||
$promise->then(
|
|
||||||
function($nextValue) use (&$actualNextValue, &$onFulfilledCalled) {
|
|
||||||
$onFulfilledCalled = true;
|
|
||||||
$actualNextValue = $nextValue;
|
|
||||||
},
|
|
||||||
function(\Exception $reason) use (&$actualNextReason, &$onRejectedCalled) {
|
|
||||||
$onRejectedCalled = true;
|
|
||||||
$actualNextReason = $reason->getMessage();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertSame($onFulfilledCalled, false);
|
|
||||||
$this->assertSame($onRejectedCalled, false);
|
|
||||||
|
|
||||||
SyncPromise::runQueue();
|
|
||||||
|
|
||||||
if ($expectedNextState !== SyncPromise::PENDING) {
|
|
||||||
$this->assertSame(!$expectedNextReason, $onFulfilledCalled);
|
|
||||||
$this->assertSame(!!$expectedNextReason, $onRejectedCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertSame($expectedNextValue, $actualNextValue);
|
|
||||||
$this->assertSame($expectedNextReason, $actualNextReason);
|
|
||||||
$this->assertSame($expectedNextState, $promise->adoptedPromise->state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,32 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor\Promise;
|
namespace GraphQL\Tests\Executor\Promise;
|
||||||
|
|
||||||
use GraphQL\Executor\Promise\Adapter\SyncPromise;
|
use GraphQL\Executor\Promise\Adapter\SyncPromise;
|
||||||
use PHPUnit\Framework\Error\Error;
|
use PHPUnit\Framework\Error\Error;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function uniqid;
|
||||||
|
|
||||||
class SyncPromiseTest extends TestCase
|
class SyncPromiseTest extends TestCase
|
||||||
{
|
{
|
||||||
public function getFulfilledPromiseResolveData()
|
public function getFulfilledPromiseResolveData()
|
||||||
{
|
{
|
||||||
$onFulfilledReturnsNull = function() {
|
$onFulfilledReturnsNull = function () {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
$onFulfilledReturnsSameValue = function($value) {
|
|
||||||
|
$onFulfilledReturnsSameValue = function ($value) {
|
||||||
return $value;
|
return $value;
|
||||||
};
|
};
|
||||||
$onFulfilledReturnsOtherValue = function($value) {
|
|
||||||
|
$onFulfilledReturnsOtherValue = function ($value) {
|
||||||
return 'other-' . $value;
|
return 'other-' . $value;
|
||||||
};
|
};
|
||||||
$onFulfilledThrows = function($value) {
|
|
||||||
throw new \Exception("onFulfilled throws this!");
|
$onFulfilledThrows = function ($value) {
|
||||||
|
throw new \Exception('onFulfilled throws this!');
|
||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -28,7 +35,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
[uniqid(), $onFulfilledReturnsNull, null, null, SyncPromise::FULFILLED],
|
[uniqid(), $onFulfilledReturnsNull, null, null, SyncPromise::FULFILLED],
|
||||||
['test-value', $onFulfilledReturnsSameValue, 'test-value', null, SyncPromise::FULFILLED],
|
['test-value', $onFulfilledReturnsSameValue, 'test-value', null, SyncPromise::FULFILLED],
|
||||||
['test-value-2', $onFulfilledReturnsOtherValue, 'other-test-value-2', null, SyncPromise::FULFILLED],
|
['test-value-2', $onFulfilledReturnsOtherValue, 'other-test-value-2', null, SyncPromise::FULFILLED],
|
||||||
['test-value-3', $onFulfilledThrows, null, "onFulfilled throws this!", SyncPromise::REJECTED],
|
['test-value-3', $onFulfilledThrows, null, 'onFulfilled throws this!', SyncPromise::REJECTED],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,8 +48,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
@ -63,8 +69,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
@ -85,21 +90,27 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
$promise->resolve($resolvedValue);
|
$promise->resolve($resolvedValue);
|
||||||
$this->assertEquals(SyncPromise::FULFILLED, $promise->state);
|
$this->assertEquals(SyncPromise::FULFILLED, $promise->state);
|
||||||
|
|
||||||
$nextPromise = $promise->then(null, function() {});
|
$nextPromise = $promise->then(
|
||||||
|
null,
|
||||||
|
function () {
|
||||||
|
}
|
||||||
|
);
|
||||||
$this->assertSame($promise, $nextPromise);
|
$this->assertSame($promise, $nextPromise);
|
||||||
|
|
||||||
$onRejectedCalled = false;
|
$onRejectedCalled = false;
|
||||||
$nextPromise = $promise->then($onFulfilled, function () use (&$onRejectedCalled) {
|
$nextPromise = $promise->then(
|
||||||
|
$onFulfilled,
|
||||||
|
function () use (&$onRejectedCalled) {
|
||||||
$onRejectedCalled = true;
|
$onRejectedCalled = true;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if ($onFulfilled) {
|
if ($onFulfilled) {
|
||||||
$this->assertNotSame($promise, $nextPromise);
|
$this->assertNotSame($promise, $nextPromise);
|
||||||
@ -124,19 +135,57 @@ class SyncPromiseTest extends TestCase
|
|||||||
$this->assertValidPromise($nextPromise3, $expectedNextReason, $expectedNextValue, $expectedNextState);
|
$this->assertValidPromise($nextPromise3, $expectedNextReason, $expectedNextValue, $expectedNextState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function assertValidPromise(
|
||||||
|
SyncPromise $promise,
|
||||||
|
$expectedNextReason,
|
||||||
|
$expectedNextValue,
|
||||||
|
$expectedNextState
|
||||||
|
) {
|
||||||
|
$actualNextValue = null;
|
||||||
|
$actualNextReason = null;
|
||||||
|
$onFulfilledCalled = false;
|
||||||
|
$onRejectedCalled = false;
|
||||||
|
|
||||||
|
$promise->then(
|
||||||
|
function ($nextValue) use (&$actualNextValue, &$onFulfilledCalled) {
|
||||||
|
$onFulfilledCalled = true;
|
||||||
|
$actualNextValue = $nextValue;
|
||||||
|
},
|
||||||
|
function (\Throwable $reason) use (&$actualNextReason, &$onRejectedCalled) {
|
||||||
|
$onRejectedCalled = true;
|
||||||
|
$actualNextReason = $reason->getMessage();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($onFulfilledCalled, false);
|
||||||
|
$this->assertEquals($onRejectedCalled, false);
|
||||||
|
|
||||||
|
SyncPromise::runQueue();
|
||||||
|
|
||||||
|
$this->assertEquals(! $expectedNextReason, $onFulfilledCalled);
|
||||||
|
$this->assertEquals(! ! $expectedNextReason, $onRejectedCalled);
|
||||||
|
|
||||||
|
$this->assertEquals($expectedNextValue, $actualNextValue);
|
||||||
|
$this->assertEquals($expectedNextReason, $actualNextReason);
|
||||||
|
$this->assertEquals($expectedNextState, $promise->state);
|
||||||
|
}
|
||||||
|
|
||||||
public function getRejectedPromiseData()
|
public function getRejectedPromiseData()
|
||||||
{
|
{
|
||||||
$onRejectedReturnsNull = function() {
|
$onRejectedReturnsNull = function () {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
$onRejectedReturnsSomeValue = function($reason) {
|
|
||||||
|
$onRejectedReturnsSomeValue = function ($reason) {
|
||||||
return 'some-value';
|
return 'some-value';
|
||||||
};
|
};
|
||||||
$onRejectedThrowsSameReason = function($reason) {
|
|
||||||
|
$onRejectedThrowsSameReason = function ($reason) {
|
||||||
throw $reason;
|
throw $reason;
|
||||||
};
|
};
|
||||||
$onRejectedThrowsOtherReason = function($value) {
|
|
||||||
throw new \Exception("onRejected throws other!");
|
$onRejectedThrowsOtherReason = function ($value) {
|
||||||
|
throw new \Exception('onRejected throws other!');
|
||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -158,8 +207,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
@ -169,7 +217,6 @@ class SyncPromiseTest extends TestCase
|
|||||||
$this->expectException(\Throwable::class);
|
$this->expectException(\Throwable::class);
|
||||||
$this->expectExceptionMessage('Cannot change rejection reason');
|
$this->expectExceptionMessage('Cannot change rejection reason');
|
||||||
$promise->reject(new \Exception('other-reason'));
|
$promise->reject(new \Exception('other-reason'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -181,8 +228,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
@ -203,8 +249,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
$expectedNextValue,
|
$expectedNextValue,
|
||||||
$expectedNextReason,
|
$expectedNextReason,
|
||||||
$expectedNextState
|
$expectedNextState
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
|
|
||||||
@ -214,18 +259,22 @@ class SyncPromiseTest extends TestCase
|
|||||||
try {
|
try {
|
||||||
$promise->reject(new \Exception('other-reason'));
|
$promise->reject(new \Exception('other-reason'));
|
||||||
$this->fail('Expected exception not thrown');
|
$this->fail('Expected exception not thrown');
|
||||||
} catch (\Exception $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->assertEquals('Cannot change rejection reason', $e->getMessage());
|
$this->assertEquals('Cannot change rejection reason', $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$promise->resolve('anything');
|
$promise->resolve('anything');
|
||||||
$this->fail('Expected exception not thrown');
|
$this->fail('Expected exception not thrown');
|
||||||
} catch (\Exception $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->assertEquals('Cannot resolve rejected promise', $e->getMessage());
|
$this->assertEquals('Cannot resolve rejected promise', $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
$nextPromise = $promise->then(function() {}, null);
|
$nextPromise = $promise->then(
|
||||||
|
function () {
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
$this->assertSame($promise, $nextPromise);
|
$this->assertSame($promise, $nextPromise);
|
||||||
|
|
||||||
$onFulfilledCalled = false;
|
$onFulfilledCalled = false;
|
||||||
@ -266,7 +315,7 @@ class SyncPromiseTest extends TestCase
|
|||||||
try {
|
try {
|
||||||
$promise->resolve($promise);
|
$promise->resolve($promise);
|
||||||
$this->fail('Expected exception not thrown');
|
$this->fail('Expected exception not thrown');
|
||||||
} catch (\Exception $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->assertEquals('Cannot resolve promise with self', $e->getMessage());
|
$this->assertEquals('Cannot resolve promise with self', $e->getMessage());
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
}
|
}
|
||||||
@ -299,24 +348,25 @@ class SyncPromiseTest extends TestCase
|
|||||||
throw $e;
|
throw $e;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$promise->reject(new \Exception("Rejected Reason"));
|
$promise->reject(new \Exception('Rejected Reason'));
|
||||||
$this->assertValidPromise($promise, "Rejected Reason", null, SyncPromise::REJECTED);
|
$this->assertValidPromise($promise, 'Rejected Reason', null, SyncPromise::REJECTED);
|
||||||
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$promise2 = $promise->then(null, function() {
|
$promise2 = $promise->then(
|
||||||
|
null,
|
||||||
|
function () {
|
||||||
return 'value';
|
return 'value';
|
||||||
});
|
}
|
||||||
$promise->reject(new \Exception("Rejected Again"));
|
);
|
||||||
|
$promise->reject(new \Exception('Rejected Again'));
|
||||||
$this->assertValidPromise($promise2, null, 'value', SyncPromise::FULFILLED);
|
$this->assertValidPromise($promise2, null, 'value', SyncPromise::FULFILLED);
|
||||||
|
|
||||||
$promise = new SyncPromise();
|
$promise = new SyncPromise();
|
||||||
$promise2 = $promise->then();
|
$promise2 = $promise->then();
|
||||||
$promise->reject(new \Exception("Rejected Once Again"));
|
$promise->reject(new \Exception('Rejected Once Again'));
|
||||||
$this->assertValidPromise($promise2, "Rejected Once Again", null, SyncPromise::REJECTED);
|
$this->assertValidPromise($promise2, 'Rejected Once Again', null, SyncPromise::REJECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPendingPromiseThen() : void
|
public function testPendingPromiseThen() : void
|
||||||
@ -332,11 +382,13 @@ class SyncPromiseTest extends TestCase
|
|||||||
// Make sure that it queues derivative promises until resolution:
|
// Make sure that it queues derivative promises until resolution:
|
||||||
$onFulfilledCount = 0;
|
$onFulfilledCount = 0;
|
||||||
$onRejectedCount = 0;
|
$onRejectedCount = 0;
|
||||||
$onFulfilled = function($value) use (&$onFulfilledCount) {
|
$onFulfilled = function ($value) use (&$onFulfilledCount) {
|
||||||
$onFulfilledCount++;
|
$onFulfilledCount++;
|
||||||
|
|
||||||
return $onFulfilledCount;
|
return $onFulfilledCount;
|
||||||
};
|
};
|
||||||
$onRejected = function($reason) use (&$onRejectedCount) {
|
|
||||||
|
$onRejected = function ($reason) use (&$onRejectedCount) {
|
||||||
$onRejectedCount++;
|
$onRejectedCount++;
|
||||||
throw $reason;
|
throw $reason;
|
||||||
};
|
};
|
||||||
@ -367,35 +419,4 @@ class SyncPromiseTest extends TestCase
|
|||||||
$this->assertValidPromise($nextPromise3, null, 2, SyncPromise::FULFILLED);
|
$this->assertValidPromise($nextPromise3, null, 2, SyncPromise::FULFILLED);
|
||||||
$this->assertValidPromise($nextPromise4, null, 3, SyncPromise::FULFILLED);
|
$this->assertValidPromise($nextPromise4, null, 3, SyncPromise::FULFILLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function assertValidPromise(SyncPromise $promise, $expectedNextReason, $expectedNextValue, $expectedNextState)
|
|
||||||
{
|
|
||||||
$actualNextValue = null;
|
|
||||||
$actualNextReason = null;
|
|
||||||
$onFulfilledCalled = false;
|
|
||||||
$onRejectedCalled = false;
|
|
||||||
|
|
||||||
$promise->then(
|
|
||||||
function($nextValue) use (&$actualNextValue, &$onFulfilledCalled) {
|
|
||||||
$onFulfilledCalled = true;
|
|
||||||
$actualNextValue = $nextValue;
|
|
||||||
},
|
|
||||||
function(\Exception $reason) use (&$actualNextReason, &$onRejectedCalled) {
|
|
||||||
$onRejectedCalled = true;
|
|
||||||
$actualNextReason = $reason->getMessage();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals($onFulfilledCalled, false);
|
|
||||||
$this->assertEquals($onRejectedCalled, false);
|
|
||||||
|
|
||||||
SyncPromise::runQueue();
|
|
||||||
|
|
||||||
$this->assertEquals(!$expectedNextReason, $onFulfilledCalled);
|
|
||||||
$this->assertEquals(!!$expectedNextReason, $onRejectedCalled);
|
|
||||||
|
|
||||||
$this->assertEquals($expectedNextValue, $actualNextValue);
|
|
||||||
$this->assertEquals($expectedNextReason, $actualNextReason);
|
|
||||||
$this->assertEquals($expectedNextState, $promise->state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,22 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Tests\Executor\TestClasses\Adder;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function json_encode;
|
||||||
|
use function uniqid;
|
||||||
|
|
||||||
class ResolveTest extends TestCase
|
class ResolveTest extends TestCase
|
||||||
{
|
{
|
||||||
// Execute: resolve function
|
// Execute: resolve function
|
||||||
|
|
||||||
private function buildSchema($testField)
|
|
||||||
{
|
|
||||||
return new Schema([
|
|
||||||
'query' => new ObjectType([
|
|
||||||
'name' => 'Query',
|
|
||||||
'fields' => [
|
|
||||||
'test' => $testField
|
|
||||||
]
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('default function accesses properties')
|
* @see it('default function accesses properties')
|
||||||
*/
|
*/
|
||||||
@ -32,9 +24,7 @@ class ResolveTest extends TestCase
|
|||||||
{
|
{
|
||||||
$schema = $this->buildSchema(['type' => Type::string()]);
|
$schema = $this->buildSchema(['type' => Type::string()]);
|
||||||
|
|
||||||
$source = [
|
$source = ['test' => 'testValue'];
|
||||||
'test' => 'testValue'
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
['data' => ['test' => 'testValue']],
|
['data' => ['test' => 'testValue']],
|
||||||
@ -42,6 +32,16 @@ class ResolveTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildSchema($testField)
|
||||||
|
{
|
||||||
|
return new Schema([
|
||||||
|
'query' => new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => ['test' => $testField],
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('default function calls methods')
|
* @see it('default function calls methods')
|
||||||
*/
|
*/
|
||||||
@ -51,9 +51,9 @@ class ResolveTest extends TestCase
|
|||||||
$_secret = 'secretValue' . uniqid();
|
$_secret = 'secretValue' . uniqid();
|
||||||
|
|
||||||
$source = [
|
$source = [
|
||||||
'test' => function() use ($_secret) {
|
'test' => function () use ($_secret) {
|
||||||
return $_secret;
|
return $_secret;
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
['data' => ['test' => $_secret]],
|
['data' => ['test' => $_secret]],
|
||||||
@ -69,7 +69,7 @@ class ResolveTest extends TestCase
|
|||||||
$schema = $this->buildSchema([
|
$schema = $this->buildSchema([
|
||||||
'type' => Type::int(),
|
'type' => Type::int(),
|
||||||
'args' => [
|
'args' => [
|
||||||
'addend1' => [ 'type' => Type::int() ],
|
'addend1' => ['type' => Type::int()],
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ class ResolveTest extends TestCase
|
|||||||
],
|
],
|
||||||
'resolve' => function ($source, $args) {
|
'resolve' => function ($source, $args) {
|
||||||
return json_encode([$source, $args]);
|
return json_encode([$source, $args]);
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
use GraphQL\Error\Error;
|
|
||||||
use GraphQL\Error\FormattedError;
|
use GraphQL\Error\FormattedError;
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
@ -36,7 +38,7 @@ class SyncTest extends TestCase
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($rootValue) {
|
'resolve' => function ($rootValue) {
|
||||||
return $rootValue;
|
return $rootValue;
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'asyncField' => [
|
'asyncField' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
@ -44,9 +46,9 @@ class SyncTest extends TestCase
|
|||||||
return new Deferred(function () use ($rootValue) {
|
return new Deferred(function () use ($rootValue) {
|
||||||
return $rootValue;
|
return $rootValue;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'mutation' => new ObjectType([
|
'mutation' => new ObjectType([
|
||||||
'name' => 'Mutation',
|
'name' => 'Mutation',
|
||||||
@ -55,11 +57,12 @@ class SyncTest extends TestCase
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function ($rootValue) {
|
'resolve' => function ($rootValue) {
|
||||||
return $rootValue;
|
return $rootValue;
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->promiseAdapter = new SyncPromiseAdapter();
|
$this->promiseAdapter = new SyncPromiseAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +82,26 @@ class SyncTest extends TestCase
|
|||||||
$this->assertSync(['errors' => [['message' => 'Must provide an operation.']]], $result);
|
$this->assertSync(['errors' => [['message' => 'Must provide an operation.']]], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function execute($schema, $doc, $rootValue = null)
|
||||||
|
{
|
||||||
|
return Executor::promiseToExecute($this->promiseAdapter, $schema, $doc, $rootValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function assertSync($expectedFinalArray, $actualResult)
|
||||||
|
{
|
||||||
|
$message = 'Failed assertion that execution was synchronous';
|
||||||
|
$this->assertInstanceOf(Promise::class, $actualResult, $message);
|
||||||
|
$this->assertInstanceOf(SyncPromise::class, $actualResult->adoptedPromise, $message);
|
||||||
|
$this->assertEquals(SyncPromise::FULFILLED, $actualResult->adoptedPromise->state, $message);
|
||||||
|
$this->assertInstanceOf(ExecutionResult::class, $actualResult->adoptedPromise->result, $message);
|
||||||
|
$this->assertArraySubset(
|
||||||
|
$expectedFinalArray,
|
||||||
|
$actualResult->adoptedPromise->result->toArray(),
|
||||||
|
false,
|
||||||
|
$message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('does not return a Promise if fields are all synchronous')
|
* @see it('does not return a Promise if fields are all synchronous')
|
||||||
*/
|
*/
|
||||||
@ -93,6 +116,8 @@ class SyncTest extends TestCase
|
|||||||
$this->assertSync(['data' => ['syncField' => 'rootValue']], $result);
|
$this->assertSync(['data' => ['syncField' => 'rootValue']], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe: graphqlSync
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('does not return a Promise if mutation fields are all synchronous')
|
* @see it('does not return a Promise if mutation fields are all synchronous')
|
||||||
*/
|
*/
|
||||||
@ -121,7 +146,16 @@ class SyncTest extends TestCase
|
|||||||
$this->assertAsync(['data' => ['syncField' => 'rootValue', 'asyncField' => 'rootValue']], $result);
|
$this->assertAsync(['data' => ['syncField' => 'rootValue', 'asyncField' => 'rootValue']], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: graphqlSync
|
private function assertAsync($expectedFinalArray, $actualResult)
|
||||||
|
{
|
||||||
|
$message = 'Failed assertion that execution was asynchronous';
|
||||||
|
$this->assertInstanceOf(Promise::class, $actualResult, $message);
|
||||||
|
$this->assertInstanceOf(SyncPromise::class, $actualResult->adoptedPromise, $message);
|
||||||
|
$this->assertEquals(SyncPromise::PENDING, $actualResult->adoptedPromise->state, $message);
|
||||||
|
$resolvedResult = $this->promiseAdapter->wait($actualResult);
|
||||||
|
$this->assertInstanceOf(ExecutionResult::class, $resolvedResult, $message);
|
||||||
|
$this->assertArraySubset($expectedFinalArray, $resolvedResult->toArray(), false, $message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('does not return a Promise for syntax errors')
|
* @see it('does not return a Promise for syntax errors')
|
||||||
@ -133,12 +167,22 @@ class SyncTest extends TestCase
|
|||||||
$this->schema,
|
$this->schema,
|
||||||
$doc
|
$doc
|
||||||
);
|
);
|
||||||
$this->assertSync([
|
$this->assertSync(
|
||||||
|
[
|
||||||
'errors' => [
|
'errors' => [
|
||||||
['message' => 'Syntax Error: Expected Name, found {',
|
[
|
||||||
'locations' => [['line' => 1, 'column' => 29]]]
|
'message' => 'Syntax Error: Expected Name, found {',
|
||||||
]
|
'locations' => [['line' => 1, 'column' => 29]],
|
||||||
], $result);
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
$result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function graphqlSync($schema, $doc, $rootValue = null)
|
||||||
|
{
|
||||||
|
return GraphQL::promiseToExecute($this->promiseAdapter, $schema, $doc, $rootValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -153,9 +197,12 @@ class SyncTest extends TestCase
|
|||||||
$doc
|
$doc
|
||||||
);
|
);
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => Utils::map($validationErrors, function ($e) {
|
'errors' => Utils::map(
|
||||||
|
$validationErrors,
|
||||||
|
function ($e) {
|
||||||
return FormattedError::createFromException($e);
|
return FormattedError::createFromException($e);
|
||||||
})
|
}
|
||||||
|
),
|
||||||
];
|
];
|
||||||
$this->assertSync($expected, $result);
|
$this->assertSync($expected, $result);
|
||||||
}
|
}
|
||||||
@ -173,35 +220,4 @@ class SyncTest extends TestCase
|
|||||||
);
|
);
|
||||||
$this->assertSync(['data' => ['syncField' => 'rootValue']], $result);
|
$this->assertSync(['data' => ['syncField' => 'rootValue']], $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function graphqlSync($schema, $doc, $rootValue = null)
|
|
||||||
{
|
|
||||||
return GraphQL::promiseToExecute($this->promiseAdapter, $schema, $doc, $rootValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function execute($schema, $doc, $rootValue = null)
|
|
||||||
{
|
|
||||||
return Executor::promiseToExecute($this->promiseAdapter, $schema, $doc, $rootValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function assertSync($expectedFinalArray, $actualResult)
|
|
||||||
{
|
|
||||||
$message = 'Failed assertion that execution was synchronous';
|
|
||||||
$this->assertInstanceOf(Promise::class, $actualResult, $message);
|
|
||||||
$this->assertInstanceOf(SyncPromise::class, $actualResult->adoptedPromise, $message);
|
|
||||||
$this->assertEquals(SyncPromise::FULFILLED, $actualResult->adoptedPromise->state, $message);
|
|
||||||
$this->assertInstanceOf(ExecutionResult::class, $actualResult->adoptedPromise->result, $message);
|
|
||||||
$this->assertArraySubset($expectedFinalArray, $actualResult->adoptedPromise->result->toArray(), $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function assertAsync($expectedFinalArray, $actualResult)
|
|
||||||
{
|
|
||||||
$message = 'Failed assertion that execution was asynchronous';
|
|
||||||
$this->assertInstanceOf(Promise::class, $actualResult, $message);
|
|
||||||
$this->assertInstanceOf(SyncPromise::class, $actualResult->adoptedPromise, $message);
|
|
||||||
$this->assertEquals(SyncPromise::PENDING, $actualResult->adoptedPromise->state, $message);
|
|
||||||
$resolvedResult = $this->promiseAdapter->wait($actualResult);
|
|
||||||
$this->assertInstanceOf(ExecutionResult::class, $resolvedResult, $message);
|
|
||||||
$this->assertArraySubset($expectedFinalArray, $resolvedResult->toArray(), $message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,128 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace GraphQL\Tests\Executor;
|
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
|
||||||
use GraphQL\Type\Definition\ScalarType;
|
|
||||||
use GraphQL\Utils\Utils;
|
|
||||||
|
|
||||||
class Dog
|
|
||||||
{
|
|
||||||
function __construct($name, $woofs)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->woofs = $woofs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Cat
|
|
||||||
{
|
|
||||||
function __construct($name, $meows)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->meows = $meows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Human
|
|
||||||
{
|
|
||||||
function __construct($name)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Person
|
|
||||||
{
|
|
||||||
public $name;
|
|
||||||
public $pets;
|
|
||||||
public $friends;
|
|
||||||
|
|
||||||
function __construct($name, $pets = null, $friends = null)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->pets = $pets;
|
|
||||||
$this->friends = $friends;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ComplexScalar extends ScalarType
|
|
||||||
{
|
|
||||||
public static function create()
|
|
||||||
{
|
|
||||||
return new self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public $name = 'ComplexScalar';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function serialize($value)
|
|
||||||
{
|
|
||||||
if ($value === 'DeserializedValue') {
|
|
||||||
return 'SerializedValue';
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Cannot serialize value as ComplexScalar: " . Utils::printSafe($value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function parseValue($value)
|
|
||||||
{
|
|
||||||
if ($value === 'SerializedValue') {
|
|
||||||
return 'DeserializedValue';
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Cannot represent value as ComplexScalar: " . Utils::printSafe($value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function parseLiteral($valueNode, array $variables = null)
|
|
||||||
{
|
|
||||||
if ($valueNode->value === 'SerializedValue') {
|
|
||||||
return 'DeserializedValue';
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Cannot represent literal as ComplexScalar: " . Utils::printSafe($valueNode->value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Special
|
|
||||||
{
|
|
||||||
public $value;
|
|
||||||
|
|
||||||
public function __construct($value)
|
|
||||||
{
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NotSpecial
|
|
||||||
{
|
|
||||||
public $value;
|
|
||||||
|
|
||||||
public function __construct($value)
|
|
||||||
{
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Adder
|
|
||||||
{
|
|
||||||
public $num;
|
|
||||||
|
|
||||||
public $test;
|
|
||||||
|
|
||||||
public function __construct($num)
|
|
||||||
{
|
|
||||||
$this->num = $num;
|
|
||||||
|
|
||||||
$this->test = function($source, $args, $context) {
|
|
||||||
return $this->num + $args['addend1'] + $context['addend2'];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
23
tests/Executor/TestClasses/Adder.php
Normal file
23
tests/Executor/TestClasses/Adder.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Adder
|
||||||
|
{
|
||||||
|
/** @var float */
|
||||||
|
public $num;
|
||||||
|
|
||||||
|
/** @var callable */
|
||||||
|
public $test;
|
||||||
|
|
||||||
|
public function __construct(float $num)
|
||||||
|
{
|
||||||
|
$this->num = $num;
|
||||||
|
|
||||||
|
$this->test = function ($source, $args, $context) {
|
||||||
|
return $this->num + $args['addend1'] + $context['addend2'];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
20
tests/Executor/TestClasses/Cat.php
Normal file
20
tests/Executor/TestClasses/Cat.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Cat
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
public $meows;
|
||||||
|
|
||||||
|
public function __construct(string $name, bool $meows)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->meows = $meows;
|
||||||
|
}
|
||||||
|
}
|
56
tests/Executor/TestClasses/ComplexScalar.php
Normal file
56
tests/Executor/TestClasses/ComplexScalar.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
use GraphQL\Error\Error;
|
||||||
|
use GraphQL\Type\Definition\ScalarType;
|
||||||
|
use GraphQL\Utils\Utils;
|
||||||
|
|
||||||
|
class ComplexScalar extends ScalarType
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name = 'ComplexScalar';
|
||||||
|
|
||||||
|
public static function create() : self
|
||||||
|
{
|
||||||
|
return new self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function serialize($value)
|
||||||
|
{
|
||||||
|
if ($value === 'DeserializedValue') {
|
||||||
|
return 'SerializedValue';
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Cannot serialize value as ComplexScalar: ' . Utils::printSafe($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function parseValue($value)
|
||||||
|
{
|
||||||
|
if ($value === 'SerializedValue') {
|
||||||
|
return 'DeserializedValue';
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Cannot represent value as ComplexScalar: ' . Utils::printSafe($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function parseLiteral($valueNode, ?array $variables = null)
|
||||||
|
{
|
||||||
|
if ($valueNode->value === 'SerializedValue') {
|
||||||
|
return 'DeserializedValue';
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Cannot represent literal as ComplexScalar: ' . Utils::printSafe($valueNode->value));
|
||||||
|
}
|
||||||
|
}
|
20
tests/Executor/TestClasses/Dog.php
Normal file
20
tests/Executor/TestClasses/Dog.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Dog
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
public $woofs;
|
||||||
|
|
||||||
|
public function __construct(string $name, bool $woofs)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->woofs = $woofs;
|
||||||
|
}
|
||||||
|
}
|
16
tests/Executor/TestClasses/Human.php
Normal file
16
tests/Executor/TestClasses/Human.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Human
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
public function __construct(string $name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
}
|
19
tests/Executor/TestClasses/NotSpecial.php
Normal file
19
tests/Executor/TestClasses/NotSpecial.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class NotSpecial
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function __construct($value)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
}
|
16
tests/Executor/TestClasses/NumberHolder.php
Normal file
16
tests/Executor/TestClasses/NumberHolder.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class NumberHolder
|
||||||
|
{
|
||||||
|
/** @var float */
|
||||||
|
public $theNumber;
|
||||||
|
|
||||||
|
public function __construct(float $originalNumber)
|
||||||
|
{
|
||||||
|
$this->theNumber = $originalNumber;
|
||||||
|
}
|
||||||
|
}
|
28
tests/Executor/TestClasses/Person.php
Normal file
28
tests/Executor/TestClasses/Person.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Person
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
/** @var (Dog|Cat)[]|null */
|
||||||
|
public $pets;
|
||||||
|
|
||||||
|
/** @var (Dog|Cat|Person)[]|null */
|
||||||
|
public $friends;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param (Cat|Dog)[]|null $pets
|
||||||
|
* @param (Cat|Dog|Person)[]|null $friends
|
||||||
|
*/
|
||||||
|
public function __construct(string $name, $pets = null, $friends = null)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->pets = $pets;
|
||||||
|
$this->friends = $friends;
|
||||||
|
}
|
||||||
|
}
|
44
tests/Executor/TestClasses/Root.php
Normal file
44
tests/Executor/TestClasses/Root.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
use GraphQL\Deferred;
|
||||||
|
|
||||||
|
class Root
|
||||||
|
{
|
||||||
|
/** @var NumberHolder */
|
||||||
|
public $numberHolder;
|
||||||
|
|
||||||
|
public function __construct(float $originalNumber)
|
||||||
|
{
|
||||||
|
$this->numberHolder = new NumberHolder($originalNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function promiseToChangeTheNumber($newNumber) : Deferred
|
||||||
|
{
|
||||||
|
return new Deferred(function () use ($newNumber) {
|
||||||
|
return $this->immediatelyChangeTheNumber($newNumber);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function immediatelyChangeTheNumber($newNumber) : NumberHolder
|
||||||
|
{
|
||||||
|
$this->numberHolder->theNumber = $newNumber;
|
||||||
|
|
||||||
|
return $this->numberHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function failToChangeTheNumber() : void
|
||||||
|
{
|
||||||
|
throw new \Exception('Cannot change the number');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function promiseAndFailToChangeTheNumber() : Deferred
|
||||||
|
{
|
||||||
|
return new Deferred(function () {
|
||||||
|
$this->failToChangeTheNumber();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
19
tests/Executor/TestClasses/Special.php
Normal file
19
tests/Executor/TestClasses/Special.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor\TestClasses;
|
||||||
|
|
||||||
|
class Special
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function __construct($value)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,38 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
|
||||||
|
|
||||||
use GraphQL\Error\Warning;
|
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Tests\Executor\TestClasses\Cat;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Dog;
|
||||||
|
use GraphQL\Tests\Executor\TestClasses\Person;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\ResolveInfo;
|
use GraphQL\Type\Definition\ResolveInfo;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\UnionType;
|
use GraphQL\Type\Definition\UnionType;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class UnionInterfaceTest extends TestCase
|
class UnionInterfaceTest extends TestCase
|
||||||
{
|
{
|
||||||
|
/** @var */
|
||||||
public $schema;
|
public $schema;
|
||||||
|
|
||||||
|
/** @var Cat */
|
||||||
public $garfield;
|
public $garfield;
|
||||||
|
|
||||||
|
/** @var Dog */
|
||||||
public $odie;
|
public $odie;
|
||||||
|
|
||||||
|
/** @var Person */
|
||||||
public $liz;
|
public $liz;
|
||||||
|
|
||||||
|
/** @var Person */
|
||||||
public $john;
|
public $john;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -28,8 +40,8 @@ class UnionInterfaceTest extends TestCase
|
|||||||
$NamedType = new InterfaceType([
|
$NamedType = new InterfaceType([
|
||||||
'name' => 'Named',
|
'name' => 'Named',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$DogType = new ObjectType([
|
$DogType = new ObjectType([
|
||||||
@ -37,11 +49,11 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'interfaces' => [$NamedType],
|
'interfaces' => [$NamedType],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'woofs' => ['type' => Type::boolean()]
|
'woofs' => ['type' => Type::boolean()],
|
||||||
],
|
],
|
||||||
'isTypeOf' => function ($value) {
|
'isTypeOf' => function ($value) {
|
||||||
return $value instanceof Dog;
|
return $value instanceof Dog;
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$CatType = new ObjectType([
|
$CatType = new ObjectType([
|
||||||
@ -49,11 +61,11 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'interfaces' => [$NamedType],
|
'interfaces' => [$NamedType],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'meows' => ['type' => Type::boolean()]
|
'meows' => ['type' => Type::boolean()],
|
||||||
],
|
],
|
||||||
'isTypeOf' => function ($value) {
|
'isTypeOf' => function ($value) {
|
||||||
return $value instanceof Cat;
|
return $value instanceof Cat;
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PetType = new UnionType([
|
$PetType = new UnionType([
|
||||||
@ -66,7 +78,7 @@ class UnionInterfaceTest extends TestCase
|
|||||||
if ($value instanceof Cat) {
|
if ($value instanceof Cat) {
|
||||||
return $CatType;
|
return $CatType;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PersonType = new ObjectType([
|
$PersonType = new ObjectType([
|
||||||
@ -75,23 +87,22 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'pets' => ['type' => Type::listOf($PetType)],
|
'pets' => ['type' => Type::listOf($PetType)],
|
||||||
'friends' => ['type' => Type::listOf($NamedType)]
|
'friends' => ['type' => Type::listOf($NamedType)],
|
||||||
],
|
],
|
||||||
'isTypeOf' => function ($value) {
|
'isTypeOf' => function ($value) {
|
||||||
return $value instanceof Person;
|
return $value instanceof Person;
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->schema = new Schema([
|
$this->schema = new Schema([
|
||||||
'query' => $PersonType,
|
'query' => $PersonType,
|
||||||
'types' => [ $PetType ]
|
'types' => [$PetType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->garfield = new Cat('Garfield', false);
|
$this->garfield = new Cat('Garfield', false);
|
||||||
$this->odie = new Dog('Odie', true);
|
$this->odie = new Dog('Odie', true);
|
||||||
$this->liz = new Person('Liz');
|
$this->liz = new Person('Liz');
|
||||||
$this->john = new Person('John', [$this->garfield, $this->odie], [$this->liz, $this->odie]);
|
$this->john = new Person('John', [$this->garfield, $this->odie], [$this->liz, $this->odie]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute: Union and intersection types
|
// Execute: Union and intersection types
|
||||||
@ -101,7 +112,6 @@ class UnionInterfaceTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testCanIntrospectOnUnionAndIntersectionTypes() : void
|
public function testCanIntrospectOnUnionAndIntersectionTypes() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$ast = Parser::parse('
|
$ast = Parser::parse('
|
||||||
{
|
{
|
||||||
Named: __type(name: "Named") {
|
Named: __type(name: "Named") {
|
||||||
@ -131,16 +141,16 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'kind' => 'INTERFACE',
|
'kind' => 'INTERFACE',
|
||||||
'name' => 'Named',
|
'name' => 'Named',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
['name' => 'name']
|
['name' => 'name'],
|
||||||
],
|
],
|
||||||
'interfaces' => null,
|
'interfaces' => null,
|
||||||
'possibleTypes' => [
|
'possibleTypes' => [
|
||||||
['name' => 'Person'],
|
['name' => 'Person'],
|
||||||
['name' => 'Dog'],
|
['name' => 'Dog'],
|
||||||
['name' => 'Cat']
|
['name' => 'Cat'],
|
||||||
],
|
],
|
||||||
'enumValues' => null,
|
'enumValues' => null,
|
||||||
'inputFields' => null
|
'inputFields' => null,
|
||||||
],
|
],
|
||||||
'Pet' => [
|
'Pet' => [
|
||||||
'kind' => 'UNION',
|
'kind' => 'UNION',
|
||||||
@ -149,12 +159,12 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'interfaces' => null,
|
'interfaces' => null,
|
||||||
'possibleTypes' => [
|
'possibleTypes' => [
|
||||||
['name' => 'Dog'],
|
['name' => 'Dog'],
|
||||||
['name' => 'Cat']
|
['name' => 'Cat'],
|
||||||
],
|
],
|
||||||
'enumValues' => null,
|
'enumValues' => null,
|
||||||
'inputFields' => null
|
'inputFields' => null,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast)->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast)->toArray());
|
||||||
}
|
}
|
||||||
@ -183,9 +193,9 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'name' => 'John',
|
'name' => 'John',
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
||||||
@ -220,10 +230,10 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'name' => 'John',
|
'name' => 'John',
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
]
|
],
|
||||||
|
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
||||||
}
|
}
|
||||||
@ -252,9 +262,9 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'name' => 'John',
|
'name' => 'John',
|
||||||
'friends' => [
|
'friends' => [
|
||||||
['__typename' => 'Person', 'name' => 'Liz'],
|
['__typename' => 'Person', 'name' => 'Liz'],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
||||||
@ -288,9 +298,9 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'name' => 'John',
|
'name' => 'John',
|
||||||
'friends' => [
|
'friends' => [
|
||||||
['__typename' => 'Person', 'name' => 'Liz'],
|
['__typename' => 'Person', 'name' => 'Liz'],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray(true));
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray(true));
|
||||||
@ -339,13 +349,13 @@ class UnionInterfaceTest extends TestCase
|
|||||||
'name' => 'John',
|
'name' => 'John',
|
||||||
'pets' => [
|
'pets' => [
|
||||||
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
],
|
],
|
||||||
'friends' => [
|
'friends' => [
|
||||||
['__typename' => 'Person', 'name' => 'Liz'],
|
['__typename' => 'Person', 'name' => 'Liz'],
|
||||||
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]
|
['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
||||||
@ -364,14 +374,25 @@ class UnionInterfaceTest extends TestCase
|
|||||||
$NamedType2 = new InterfaceType([
|
$NamedType2 = new InterfaceType([
|
||||||
'name' => 'Named',
|
'name' => 'Named',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'name' => ['type' => Type::string()]
|
'name' => ['type' => Type::string()],
|
||||||
],
|
],
|
||||||
'resolveType' => function ($obj, $context, ResolveInfo $info) use (&$encounteredContext, &$encounteredSchema, &$encounteredRootValue, &$PersonType2) {
|
'resolveType' => function (
|
||||||
|
$obj,
|
||||||
|
$context,
|
||||||
|
ResolveInfo $info
|
||||||
|
) use (
|
||||||
|
&$encounteredContext,
|
||||||
|
&
|
||||||
|
$encounteredSchema,
|
||||||
|
&$encounteredRootValue,
|
||||||
|
&$PersonType2
|
||||||
|
) {
|
||||||
$encounteredContext = $context;
|
$encounteredContext = $context;
|
||||||
$encounteredSchema = $info->schema;
|
$encounteredSchema = $info->schema;
|
||||||
$encounteredRootValue = $info->rootValue;
|
$encounteredRootValue = $info->rootValue;
|
||||||
|
|
||||||
return $PersonType2;
|
return $PersonType2;
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$PersonType2 = new ObjectType([
|
$PersonType2 = new ObjectType([
|
||||||
@ -383,9 +404,7 @@ class UnionInterfaceTest extends TestCase
|
|||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema2 = new Schema([
|
$schema2 = new Schema(['query' => $PersonType2]);
|
||||||
'query' => $PersonType2
|
|
||||||
]);
|
|
||||||
|
|
||||||
$john2 = new Person('John', [], [$this->liz]);
|
$john2 = new Person('John', [], [$this->liz]);
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Executor;
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Executor\Values;
|
use GraphQL\Executor\Values;
|
||||||
@ -10,19 +13,97 @@ use GraphQL\Type\Definition\ObjectType;
|
|||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function count;
|
||||||
|
use function var_export;
|
||||||
|
use const PHP_EOL;
|
||||||
|
|
||||||
class ValuesTest extends TestCase
|
class ValuesTest extends TestCase
|
||||||
{
|
{
|
||||||
|
/** @var Schema */
|
||||||
|
private static $schema;
|
||||||
|
|
||||||
public function testGetIDVariableValues() : void
|
public function testGetIDVariableValues() : void
|
||||||
{
|
{
|
||||||
$this->expectInputVariablesMatchOutputVariables(['idInput' => '123456789']);
|
$this->expectInputVariablesMatchOutputVariables(['idInput' => '123456789']);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
['errors'=> [], 'coerced' => ['idInput' => '123456789']],
|
['errors' => [], 'coerced' => ['idInput' => '123456789']],
|
||||||
self::runTestCase(['idInput' => 123456789]),
|
$this->runTestCase(['idInput' => 123456789]),
|
||||||
'Integer ID was not converted to string'
|
'Integer ID was not converted to string'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function expectInputVariablesMatchOutputVariables($variables) : void
|
||||||
|
{
|
||||||
|
$this->assertEquals(
|
||||||
|
$variables,
|
||||||
|
$this->runTestCase($variables)['coerced'],
|
||||||
|
'Output variables did not match input variables' . PHP_EOL . var_export($variables, true) . PHP_EOL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[] $variables
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
private function runTestCase($variables) : array
|
||||||
|
{
|
||||||
|
return Values::getVariableValues(self::getSchema(), self::getVariableDefinitionNodes(), $variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getSchema() : Schema
|
||||||
|
{
|
||||||
|
if (! self::$schema) {
|
||||||
|
self::$schema = new Schema([
|
||||||
|
'query' => new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => [
|
||||||
|
'test' => [
|
||||||
|
'type' => Type::boolean(),
|
||||||
|
'args' => [
|
||||||
|
'idInput' => Type::id(),
|
||||||
|
'boolInput' => Type::boolean(),
|
||||||
|
'intInput' => Type::int(),
|
||||||
|
'stringInput' => Type::string(),
|
||||||
|
'floatInput' => Type::float(),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return VariableDefinitionNode[]
|
||||||
|
*/
|
||||||
|
private static function getVariableDefinitionNodes() : array
|
||||||
|
{
|
||||||
|
$idInputDefinition = new VariableDefinitionNode([
|
||||||
|
'variable' => new VariableNode(['name' => new NameNode(['value' => 'idInput'])]),
|
||||||
|
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'ID'])]),
|
||||||
|
]);
|
||||||
|
$boolInputDefinition = new VariableDefinitionNode([
|
||||||
|
'variable' => new VariableNode(['name' => new NameNode(['value' => 'boolInput'])]),
|
||||||
|
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Boolean'])]),
|
||||||
|
]);
|
||||||
|
$intInputDefinition = new VariableDefinitionNode([
|
||||||
|
'variable' => new VariableNode(['name' => new NameNode(['value' => 'intInput'])]),
|
||||||
|
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Int'])]),
|
||||||
|
]);
|
||||||
|
$stringInputDefintion = new VariableDefinitionNode([
|
||||||
|
'variable' => new VariableNode(['name' => new NameNode(['value' => 'stringInput'])]),
|
||||||
|
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'String'])]),
|
||||||
|
]);
|
||||||
|
$floatInputDefinition = new VariableDefinitionNode([
|
||||||
|
'variable' => new VariableNode(['name' => new NameNode(['value' => 'floatInput'])]),
|
||||||
|
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Float'])]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [$idInputDefinition, $boolInputDefinition, $intInputDefinition, $stringInputDefintion, $floatInputDefinition];
|
||||||
|
}
|
||||||
|
|
||||||
public function testGetBooleanVariableValues() : void
|
public function testGetBooleanVariableValues() : void
|
||||||
{
|
{
|
||||||
$this->expectInputVariablesMatchOutputVariables(['boolInput' => true]);
|
$this->expectInputVariablesMatchOutputVariables(['boolInput' => true]);
|
||||||
@ -64,11 +145,20 @@ class ValuesTest extends TestCase
|
|||||||
$this->expectGraphQLError(['idInput' => true]);
|
$this->expectGraphQLError(['idInput' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function expectGraphQLError($variables) : void
|
||||||
|
{
|
||||||
|
$result = $this->runTestCase($variables);
|
||||||
|
$this->assertGreaterThan(0, count($result['errors']));
|
||||||
|
}
|
||||||
|
|
||||||
public function testFloatForIDVariableThrowsError() : void
|
public function testFloatForIDVariableThrowsError() : void
|
||||||
{
|
{
|
||||||
$this->expectGraphQLError(['idInput' => 1.0]);
|
$this->expectGraphQLError(['idInput' => 1.0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers for running test cases and making assertions
|
||||||
|
*/
|
||||||
public function testStringForBooleanVariableThrowsError() : void
|
public function testStringForBooleanVariableThrowsError() : void
|
||||||
{
|
{
|
||||||
$this->expectGraphQLError(['boolInput' => 'true']);
|
$this->expectGraphQLError(['boolInput' => 'true']);
|
||||||
@ -98,77 +188,4 @@ class ValuesTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectGraphQLError(['intInput' => -2147483649]);
|
$this->expectGraphQLError(['intInput' => -2147483649]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers for running test cases and making assertions
|
|
||||||
|
|
||||||
private function expectInputVariablesMatchOutputVariables($variables)
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
$variables,
|
|
||||||
self::runTestCase($variables)['coerced'],
|
|
||||||
'Output variables did not match input variables' . PHP_EOL . var_export($variables, true) . PHP_EOL
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function expectGraphQLError($variables)
|
|
||||||
{
|
|
||||||
$result = self::runTestCase($variables);
|
|
||||||
$this->assertGreaterThan(0, count($result['errors']));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static $schema;
|
|
||||||
|
|
||||||
private static function getSchema()
|
|
||||||
{
|
|
||||||
if (!self::$schema) {
|
|
||||||
self::$schema = new Schema([
|
|
||||||
'query' => new ObjectType([
|
|
||||||
'name' => 'Query',
|
|
||||||
'fields' => [
|
|
||||||
'test' => [
|
|
||||||
'type' => Type::boolean(),
|
|
||||||
'args' => [
|
|
||||||
'idInput' => Type::id(),
|
|
||||||
'boolInput' => Type::boolean(),
|
|
||||||
'intInput' => Type::int(),
|
|
||||||
'stringInput' => Type::string(),
|
|
||||||
'floatInput' => Type::float()
|
|
||||||
]
|
|
||||||
],
|
|
||||||
]
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
return self::$schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function getVariableDefinitionNodes()
|
|
||||||
{
|
|
||||||
$idInputDefinition = new VariableDefinitionNode([
|
|
||||||
'variable' => new VariableNode(['name' => new NameNode(['value' => 'idInput'])]),
|
|
||||||
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'ID'])])
|
|
||||||
]);
|
|
||||||
$boolInputDefinition = new VariableDefinitionNode([
|
|
||||||
'variable' => new VariableNode(['name' => new NameNode(['value' => 'boolInput'])]),
|
|
||||||
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Boolean'])])
|
|
||||||
]);
|
|
||||||
$intInputDefinition = new VariableDefinitionNode([
|
|
||||||
'variable' => new VariableNode(['name' => new NameNode(['value' => 'intInput'])]),
|
|
||||||
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Int'])])
|
|
||||||
]);
|
|
||||||
$stringInputDefintion = new VariableDefinitionNode([
|
|
||||||
'variable' => new VariableNode(['name' => new NameNode(['value' => 'stringInput'])]),
|
|
||||||
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'String'])])
|
|
||||||
]);
|
|
||||||
$floatInputDefinition = new VariableDefinitionNode([
|
|
||||||
'variable' => new VariableNode(['name' => new NameNode(['value' => 'floatInput'])]),
|
|
||||||
'type' => new NamedTypeNode(['name' => new NameNode(['value' => 'Float'])])
|
|
||||||
]);
|
|
||||||
return [$idInputDefinition, $boolInputDefinition, $intInputDefinition, $stringInputDefintion, $floatInputDefinition];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function runTestCase($variables)
|
|
||||||
{
|
|
||||||
return Values::getVariableValues(self::getSchema(), self::getVariableDefinitionNodes(), $variables);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Executor;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Executor;
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
use GraphQL\Executor\Executor;
|
use GraphQL\Executor\Executor;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Tests\Executor\TestClasses\ComplexScalar;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function json_encode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute: Handles inputs
|
* Execute: Handles inputs
|
||||||
@ -18,7 +21,6 @@ use PHPUnit\Framework\TestCase;
|
|||||||
*/
|
*/
|
||||||
class VariablesTest extends TestCase
|
class VariablesTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
public function testUsingInlineStructs() : void
|
public function testUsingInlineStructs() : void
|
||||||
{
|
{
|
||||||
// executes with complex input:
|
// executes with complex input:
|
||||||
@ -29,9 +31,7 @@ class VariablesTest extends TestCase
|
|||||||
');
|
');
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}'],
|
||||||
'fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
@ -77,8 +77,9 @@ class VariablesTest extends TestCase
|
|||||||
'errors' => [[
|
'errors' => [[
|
||||||
'message' => 'Argument "input" has invalid value ["foo", "bar", "baz"].',
|
'message' => 'Argument "input" has invalid value ["foo", "bar", "baz"].',
|
||||||
'path' => ['fieldWithObjectInput'],
|
'path' => ['fieldWithObjectInput'],
|
||||||
'locations' => [['line' => 3, 'column' => 39]]
|
'locations' => [['line' => 3, 'column' => 39]],
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, $result->toArray());
|
$this->assertArraySubset($expected, $result->toArray());
|
||||||
|
|
||||||
@ -94,6 +95,77 @@ class VariablesTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function executeQuery($query, $variableValues = null)
|
||||||
|
{
|
||||||
|
$document = Parser::parse($query);
|
||||||
|
|
||||||
|
return Executor::execute($this->schema(), $document, null, null, $variableValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe: Handles nullable scalars
|
||||||
|
*/
|
||||||
|
public function schema() : Schema
|
||||||
|
{
|
||||||
|
$ComplexScalarType = ComplexScalar::create();
|
||||||
|
|
||||||
|
$TestInputObject = new InputObjectType([
|
||||||
|
'name' => 'TestInputObject',
|
||||||
|
'fields' => [
|
||||||
|
'a' => ['type' => Type::string()],
|
||||||
|
'b' => ['type' => Type::listOf(Type::string())],
|
||||||
|
'c' => ['type' => Type::nonNull(Type::string())],
|
||||||
|
'd' => ['type' => $ComplexScalarType],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$TestNestedInputObject = new InputObjectType([
|
||||||
|
'name' => 'TestNestedInputObject',
|
||||||
|
'fields' => [
|
||||||
|
'na' => ['type' => Type::nonNull($TestInputObject)],
|
||||||
|
'nb' => ['type' => Type::nonNull(Type::string())],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$TestType = new ObjectType([
|
||||||
|
'name' => 'TestType',
|
||||||
|
'fields' => [
|
||||||
|
'fieldWithObjectInput' => $this->fieldWithInputArg(['type' => $TestInputObject]),
|
||||||
|
'fieldWithNullableStringInput' => $this->fieldWithInputArg(['type' => Type::string()]),
|
||||||
|
'fieldWithNonNullableStringInput' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::string())]),
|
||||||
|
'fieldWithDefaultArgumentValue' => $this->fieldWithInputArg([
|
||||||
|
'type' => Type::string(),
|
||||||
|
'defaultValue' => 'Hello World',
|
||||||
|
]),
|
||||||
|
'fieldWithNestedInputObject' => $this->fieldWithInputArg([
|
||||||
|
'type' => $TestNestedInputObject,
|
||||||
|
'defaultValue' => 'Hello World',
|
||||||
|
]),
|
||||||
|
'list' => $this->fieldWithInputArg(['type' => Type::listOf(Type::string())]),
|
||||||
|
'nnList' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::listOf(Type::string()))]),
|
||||||
|
'listNN' => $this->fieldWithInputArg(['type' => Type::listOf(Type::nonNull(Type::string()))]),
|
||||||
|
'nnListNN' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::listOf(Type::nonNull(Type::string())))]),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return new Schema(['query' => $TestType]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fieldWithInputArg($inputArg)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'args' => ['input' => $inputArg],
|
||||||
|
'resolve' => function ($_, $args) {
|
||||||
|
if (isset($args['input'])) {
|
||||||
|
return json_encode($args['input']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function testUsingVariables() : void
|
public function testUsingVariables() : void
|
||||||
{
|
{
|
||||||
$doc = '
|
$doc = '
|
||||||
@ -119,7 +191,7 @@ class VariablesTest extends TestCase
|
|||||||
');
|
');
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => ['fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}']
|
'data' => ['fieldWithObjectInput' => '{"a":"foo","b":["bar"],"c":"baz"}'],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
@ -132,12 +204,10 @@ class VariablesTest extends TestCase
|
|||||||
);
|
);
|
||||||
|
|
||||||
// executes with complex scalar input:
|
// executes with complex scalar input:
|
||||||
$params = [ 'input' => [ 'c' => 'foo', 'd' => 'SerializedValue' ] ];
|
$params = ['input' => ['c' => 'foo', 'd' => 'SerializedValue']];
|
||||||
$result = $this->executeQuery($doc, $params);
|
$result = $this->executeQuery($doc, $params);
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['fieldWithObjectInput' => '{"c":"foo","d":"DeserializedValue"}'],
|
||||||
'fieldWithObjectInput' => '{"c":"foo","d":"DeserializedValue"}'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
@ -152,15 +222,15 @@ class VariablesTest extends TestCase
|
|||||||
'{"a":"foo","b":"bar","c":null}; ' .
|
'{"a":"foo","b":"bar","c":null}; ' .
|
||||||
'Expected non-nullable type String! not to be null at value.c.',
|
'Expected non-nullable type String! not to be null at value.c.',
|
||||||
'locations' => [['line' => 2, 'column' => 21]],
|
'locations' => [['line' => 2, 'column' => 21]],
|
||||||
'category' => 'graphql'
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
// errors on incorrect type:
|
// errors on incorrect type:
|
||||||
$params = [ 'input' => 'foo bar' ];
|
$params = ['input' => 'foo bar'];
|
||||||
$result = $this->executeQuery($doc, $params);
|
$result = $this->executeQuery($doc, $params);
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
@ -168,10 +238,10 @@ class VariablesTest extends TestCase
|
|||||||
'message' =>
|
'message' =>
|
||||||
'Variable "$input" got invalid value "foo bar"; ' .
|
'Variable "$input" got invalid value "foo bar"; ' .
|
||||||
'Expected type TestInputObject to be an object.',
|
'Expected type TestInputObject to be an object.',
|
||||||
'locations' => [ [ 'line' => 2, 'column' => 21 ] ],
|
'locations' => [['line' => 2, 'column' => 21]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
@ -183,12 +253,12 @@ class VariablesTest extends TestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' =>
|
'message' =>
|
||||||
'Variable "$input" got invalid value {"a":"foo","b":"bar"}; '.
|
'Variable "$input" got invalid value {"a":"foo","b":"bar"}; ' .
|
||||||
'Field value.c of required type String! was not provided.',
|
'Field value.c of required type String! was not provided.',
|
||||||
'locations' => [['line' => 2, 'column' => 21]],
|
'locations' => [['line' => 2, 'column' => 21]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
@ -198,7 +268,7 @@ class VariablesTest extends TestCase
|
|||||||
fieldWithNestedObjectInput(input: $input)
|
fieldWithNestedObjectInput(input: $input)
|
||||||
}
|
}
|
||||||
';
|
';
|
||||||
$params = [ 'input' => [ 'na' => [ 'a' => 'foo' ] ] ];
|
$params = ['input' => ['na' => ['a' => 'foo']]];
|
||||||
|
|
||||||
$result = $this->executeQuery($nestedDoc, $params);
|
$result = $this->executeQuery($nestedDoc, $params);
|
||||||
$expected = [
|
$expected = [
|
||||||
@ -216,14 +286,13 @@ class VariablesTest extends TestCase
|
|||||||
'Field value.nb of required type String! was not provided.',
|
'Field value.nb of required type String! was not provided.',
|
||||||
'locations' => [['line' => 2, 'column' => 19]],
|
'locations' => [['line' => 2, 'column' => 19]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
|
|
||||||
// errors on addition of unknown input field
|
// errors on addition of unknown input field
|
||||||
$params = ['input' => [ 'a' => 'foo', 'b' => 'bar', 'c' => 'baz', 'extra' => 'dog' ]];
|
$params = ['input' => ['a' => 'foo', 'b' => 'bar', 'c' => 'baz', 'extra' => 'dog']];
|
||||||
$result = $this->executeQuery($doc, $params);
|
$result = $this->executeQuery($doc, $params);
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
@ -234,14 +303,12 @@ class VariablesTest extends TestCase
|
|||||||
'Field "extra" is not defined by type TestInputObject.',
|
'Field "extra" is not defined by type TestInputObject.',
|
||||||
'locations' => [['line' => 2, 'column' => 21]],
|
'locations' => [['line' => 2, 'column' => 21]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: Handles nullable scalars
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('allows nullable inputs to be omitted')
|
* @see it('allows nullable inputs to be omitted')
|
||||||
*/
|
*/
|
||||||
@ -253,7 +320,7 @@ class VariablesTest extends TestCase
|
|||||||
}
|
}
|
||||||
');
|
');
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => ['fieldWithNullableStringInput' => null]
|
'data' => ['fieldWithNullableStringInput' => null],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
@ -288,6 +355,9 @@ class VariablesTest extends TestCase
|
|||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Describe: Handles non-nullable scalars
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('allows nullable inputs to be set to null in a variable')
|
* @see it('allows nullable inputs to be set to null in a variable')
|
||||||
*/
|
*/
|
||||||
@ -332,9 +402,6 @@ class VariablesTest extends TestCase
|
|||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Describe: Handles non-nullable scalars
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('allows non-nullable inputs to be omitted given a default')
|
* @see it('allows non-nullable inputs to be omitted given a default')
|
||||||
*/
|
*/
|
||||||
@ -346,7 +413,7 @@ class VariablesTest extends TestCase
|
|||||||
}
|
}
|
||||||
');
|
');
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => ['fieldWithNonNullableStringInput' => '"default"']
|
'data' => ['fieldWithNonNullableStringInput' => '"default"'],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -367,9 +434,9 @@ class VariablesTest extends TestCase
|
|||||||
[
|
[
|
||||||
'message' => 'Variable "$value" of required type "String!" was not provided.',
|
'message' => 'Variable "$value" of required type "String!" was not provided.',
|
||||||
'locations' => [['line' => 2, 'column' => 31]],
|
'locations' => [['line' => 2, 'column' => 31]],
|
||||||
'category' => 'graphql'
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -393,8 +460,8 @@ class VariablesTest extends TestCase
|
|||||||
'Expected non-nullable type String! not to be null.',
|
'Expected non-nullable type String! not to be null.',
|
||||||
'locations' => [['line' => 2, 'column' => 31]],
|
'locations' => [['line' => 2, 'column' => 31]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -442,20 +509,22 @@ class VariablesTest extends TestCase
|
|||||||
'data' => ['fieldWithNonNullableStringInput' => null],
|
'data' => ['fieldWithNonNullableStringInput' => null],
|
||||||
'errors' => [[
|
'errors' => [[
|
||||||
'message' => 'Argument "input" of required type "String!" was not provided.',
|
'message' => 'Argument "input" of required type "String!" was not provided.',
|
||||||
'locations' => [ [ 'line' => 3, 'column' => 9 ] ],
|
'locations' => [['line' => 3, 'column' => 9]],
|
||||||
'path' => [ 'fieldWithNonNullableStringInput' ],
|
'path' => ['fieldWithNonNullableStringInput'],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe: Handles lists and nullability
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('reports error for array passed into string input')
|
* @see it('reports error for array passed into string input')
|
||||||
*/
|
*/
|
||||||
public function testReportsErrorForArrayPassedIntoStringInput() : void
|
public function testReportsErrorForArrayPassedIntoStringInput() : void
|
||||||
{
|
{
|
||||||
|
|
||||||
$doc = '
|
$doc = '
|
||||||
query SetsNonNullable($value: String!) {
|
query SetsNonNullable($value: String!) {
|
||||||
fieldWithNonNullableStringInput(input: $value)
|
fieldWithNonNullableStringInput(input: $value)
|
||||||
@ -471,9 +540,10 @@ class VariablesTest extends TestCase
|
|||||||
'String; String cannot represent an array value: [1,2,3]',
|
'String; String cannot represent an array value: [1,2,3]',
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
'locations' => [
|
'locations' => [
|
||||||
['line' => 2, 'column' => 31]
|
['line' => 2, 'column' => 31],
|
||||||
]
|
],
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -512,13 +582,12 @@ class VariablesTest extends TestCase
|
|||||||
'locations' => [['line' => 3, 'column' => 48]],
|
'locations' => [['line' => 3, 'column' => 48]],
|
||||||
'path' => ['fieldWithNonNullableStringInput'],
|
'path' => ['fieldWithNonNullableStringInput'],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: Handles lists and nullability
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('allows lists to be null')
|
* @see it('allows lists to be null')
|
||||||
*/
|
*/
|
||||||
@ -560,7 +629,7 @@ class VariablesTest extends TestCase
|
|||||||
list(input: $input)
|
list(input: $input)
|
||||||
}
|
}
|
||||||
';
|
';
|
||||||
$result = $this->executeQuery($doc, ['input' => ['A',null,'B']]);
|
$result = $this->executeQuery($doc, ['input' => ['A', null, 'B']]);
|
||||||
$expected = ['data' => ['list' => '["A",null,"B"]']];
|
$expected = ['data' => ['list' => '["A",null,"B"]']];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -584,8 +653,8 @@ class VariablesTest extends TestCase
|
|||||||
'Expected non-nullable type [String]! not to be null.',
|
'Expected non-nullable type [String]! not to be null.',
|
||||||
'locations' => [['line' => 2, 'column' => 17]],
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -615,7 +684,7 @@ class VariablesTest extends TestCase
|
|||||||
nnList(input: $input)
|
nnList(input: $input)
|
||||||
}
|
}
|
||||||
';
|
';
|
||||||
$result = $this->executeQuery($doc, ['input' => ['A',null,'B']]);
|
$result = $this->executeQuery($doc, ['input' => ['A', null, 'B']]);
|
||||||
$expected = ['data' => ['nnList' => '["A",null,"B"]']];
|
$expected = ['data' => ['nnList' => '["A",null,"B"]']];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -667,10 +736,10 @@ class VariablesTest extends TestCase
|
|||||||
'message' =>
|
'message' =>
|
||||||
'Variable "$input" got invalid value ["A",null,"B"]; ' .
|
'Variable "$input" got invalid value ["A",null,"B"]; ' .
|
||||||
'Expected non-nullable type String! not to be null at value[1].',
|
'Expected non-nullable type String! not to be null at value[1].',
|
||||||
'locations' => [ ['line' => 2, 'column' => 17] ],
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -692,10 +761,10 @@ class VariablesTest extends TestCase
|
|||||||
'message' =>
|
'message' =>
|
||||||
'Variable "$input" got invalid value null; ' .
|
'Variable "$input" got invalid value null; ' .
|
||||||
'Expected non-nullable type [String!]! not to be null.',
|
'Expected non-nullable type [String!]! not to be null.',
|
||||||
'locations' => [ ['line' => 2, 'column' => 17] ],
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -715,6 +784,8 @@ class VariablesTest extends TestCase
|
|||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe: Execute: Uses argument default values
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('does not allow non-null lists of non-nulls to contain null')
|
* @see it('does not allow non-null lists of non-nulls to contain null')
|
||||||
*/
|
*/
|
||||||
@ -732,10 +803,10 @@ class VariablesTest extends TestCase
|
|||||||
'message' =>
|
'message' =>
|
||||||
'Variable "$input" got invalid value ["A",null,"B"]; ' .
|
'Variable "$input" got invalid value ["A",null,"B"]; ' .
|
||||||
'Expected non-nullable type String! not to be null at value[1].',
|
'Expected non-nullable type String! not to be null at value[1].',
|
||||||
'locations' => [ ['line' => 2, 'column' => 17] ],
|
'locations' => [['line' => 2, 'column' => 17]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -750,7 +821,7 @@ class VariablesTest extends TestCase
|
|||||||
fieldWithObjectInput(input: $input)
|
fieldWithObjectInput(input: $input)
|
||||||
}
|
}
|
||||||
';
|
';
|
||||||
$vars = [ 'input' => [ 'list' => [ 'A', 'B' ] ] ];
|
$vars = ['input' => ['list' => ['A', 'B']]];
|
||||||
$result = $this->executeQuery($doc, $vars);
|
$result = $this->executeQuery($doc, $vars);
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
@ -760,8 +831,8 @@ class VariablesTest extends TestCase
|
|||||||
'be used as an input type.',
|
'be used as an input type.',
|
||||||
'locations' => [['line' => 2, 'column' => 25]],
|
'locations' => [['line' => 2, 'column' => 25]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -787,13 +858,12 @@ class VariablesTest extends TestCase
|
|||||||
'cannot be used as an input type.',
|
'cannot be used as an input type.',
|
||||||
'locations' => [['line' => 2, 'column' => 25]],
|
'locations' => [['line' => 2, 'column' => 25]],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: Execute: Uses argument default values
|
|
||||||
/**
|
/**
|
||||||
* @see it('when no argument provided')
|
* @see it('when no argument provided')
|
||||||
*/
|
*/
|
||||||
@ -838,80 +908,13 @@ class VariablesTest extends TestCase
|
|||||||
'errors' => [[
|
'errors' => [[
|
||||||
'message' =>
|
'message' =>
|
||||||
'Argument "input" has invalid value WRONG_TYPE.',
|
'Argument "input" has invalid value WRONG_TYPE.',
|
||||||
'locations' => [ [ 'line' => 2, 'column' => 50 ] ],
|
'locations' => [['line' => 2, 'column' => 50]],
|
||||||
'path' => [ 'fieldWithDefaultArgumentValue' ],
|
'path' => ['fieldWithDefaultArgumentValue'],
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function schema()
|
|
||||||
{
|
|
||||||
$ComplexScalarType = ComplexScalar::create();
|
|
||||||
|
|
||||||
$TestInputObject = new InputObjectType([
|
|
||||||
'name' => 'TestInputObject',
|
|
||||||
'fields' => [
|
|
||||||
'a' => ['type' => Type::string()],
|
|
||||||
'b' => ['type' => Type::listOf(Type::string())],
|
|
||||||
'c' => ['type' => Type::nonNull(Type::string())],
|
|
||||||
'd' => ['type' => $ComplexScalarType],
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$TestNestedInputObject = new InputObjectType([
|
|
||||||
'name' => 'TestNestedInputObject',
|
|
||||||
'fields' => [
|
|
||||||
'na' => [ 'type' => Type::nonNull($TestInputObject) ],
|
|
||||||
'nb' => [ 'type' => Type::nonNull(Type::string()) ],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$TestType = new ObjectType([
|
|
||||||
'name' => 'TestType',
|
|
||||||
'fields' => [
|
|
||||||
'fieldWithObjectInput' => $this->fieldWithInputArg(['type' => $TestInputObject]),
|
|
||||||
'fieldWithNullableStringInput' => $this->fieldWithInputArg(['type' => Type::string()]),
|
|
||||||
'fieldWithNonNullableStringInput' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::string())]),
|
|
||||||
'fieldWithDefaultArgumentValue' => $this->fieldWithInputArg([
|
|
||||||
'type' => Type::string(),
|
|
||||||
'defaultValue' => 'Hello World',
|
|
||||||
]),
|
|
||||||
'fieldWithNestedInputObject' => $this->fieldWithInputArg([
|
|
||||||
'type' => $TestNestedInputObject,
|
|
||||||
'defaultValue' => 'Hello World'
|
|
||||||
]),
|
|
||||||
'list' => $this->fieldWithInputArg(['type' => Type::listOf(Type::string())]),
|
|
||||||
'nnList' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::listOf(Type::string()))]),
|
|
||||||
'listNN' => $this->fieldWithInputArg(['type' => Type::listOf(Type::nonNull(Type::string()))]),
|
|
||||||
'nnListNN' => $this->fieldWithInputArg(['type' => Type::nonNull(Type::listOf(Type::nonNull(Type::string())))]),
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$schema = new Schema(['query' => $TestType]);
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function fieldWithInputArg($inputArg)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'type' => Type::string(),
|
|
||||||
'args' => ['input' => $inputArg],
|
|
||||||
'resolve' => function ($_, $args) {
|
|
||||||
if (isset($args['input'])) {
|
|
||||||
return json_encode($args['input']);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function executeQuery($query, $variableValues = null)
|
|
||||||
{
|
|
||||||
$document = Parser::parse($query);
|
|
||||||
return Executor::execute($this->schema(), $document, null, null, $variableValues);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Language;
|
namespace GraphQL\Tests\Language;
|
||||||
|
|
||||||
|
use GraphQL\Error\SyntaxError;
|
||||||
use GraphQL\Language\Lexer;
|
use GraphQL\Language\Lexer;
|
||||||
use GraphQL\Language\Source;
|
use GraphQL\Language\Source;
|
||||||
use GraphQL\Language\SourceLocation;
|
use GraphQL\Language\SourceLocation;
|
||||||
use GraphQL\Language\Token;
|
use GraphQL\Language\Token;
|
||||||
use GraphQL\Error\SyntaxError;
|
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function count;
|
||||||
|
use function json_decode;
|
||||||
|
|
||||||
class LexerTest extends TestCase
|
class LexerTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -23,6 +28,34 @@ class LexerTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function expectSyntaxError($text, $message, $location)
|
||||||
|
{
|
||||||
|
$this->expectException(SyntaxError::class);
|
||||||
|
$this->expectExceptionMessage($message);
|
||||||
|
try {
|
||||||
|
$this->lexOne($text);
|
||||||
|
} catch (SyntaxError $error) {
|
||||||
|
$this->assertEquals([$location], $error->getLocations());
|
||||||
|
throw $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $body
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
private function lexOne($body)
|
||||||
|
{
|
||||||
|
$lexer = new Lexer(new Source($body));
|
||||||
|
|
||||||
|
return $lexer->advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loc($line, $column)
|
||||||
|
{
|
||||||
|
return new SourceLocation($line, $column);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts BOM header')
|
* @see it('accepts BOM header')
|
||||||
*/
|
*/
|
||||||
@ -33,7 +66,7 @@ class LexerTest extends TestCase
|
|||||||
'kind' => Token::NAME,
|
'kind' => Token::NAME,
|
||||||
'start' => 2,
|
'start' => 2,
|
||||||
'end' => 5,
|
'end' => 5,
|
||||||
'value' => 'foo'
|
'value' => 'foo',
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, (array) $this->lexOne($bom . ' foo'));
|
$this->assertArraySubset($expected, (array) $this->lexOne($bom . ' foo'));
|
||||||
@ -50,7 +83,7 @@ class LexerTest extends TestCase
|
|||||||
'end' => 11,
|
'end' => 11,
|
||||||
'line' => 4,
|
'line' => 4,
|
||||||
'column' => 3,
|
'column' => 3,
|
||||||
'value' => 'foo'
|
'value' => 'foo',
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, (array) $this->lexOne("\n \r\n \r foo\n"));
|
$this->assertArraySubset($expected, (array) $this->lexOne("\n \r\n \r foo\n"));
|
||||||
}
|
}
|
||||||
@ -70,7 +103,7 @@ class LexerTest extends TestCase
|
|||||||
'kind' => Token::NAME,
|
'kind' => Token::NAME,
|
||||||
'start' => 6,
|
'start' => 6,
|
||||||
'end' => 9,
|
'end' => 9,
|
||||||
'value' => 'foo'
|
'value' => 'foo',
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, (array) $this->lexOne($example1));
|
$this->assertArraySubset($expected, (array) $this->lexOne($example1));
|
||||||
|
|
||||||
@ -83,7 +116,7 @@ class LexerTest extends TestCase
|
|||||||
'kind' => Token::NAME,
|
'kind' => Token::NAME,
|
||||||
'start' => 18,
|
'start' => 18,
|
||||||
'end' => 21,
|
'end' => 21,
|
||||||
'value' => 'foo'
|
'value' => 'foo',
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, (array) $this->lexOne($example2));
|
$this->assertArraySubset($expected, (array) $this->lexOne($example2));
|
||||||
|
|
||||||
@ -91,7 +124,7 @@ class LexerTest extends TestCase
|
|||||||
'kind' => Token::NAME,
|
'kind' => Token::NAME,
|
||||||
'start' => 3,
|
'start' => 3,
|
||||||
'end' => 6,
|
'end' => 6,
|
||||||
'value' => 'foo'
|
'value' => 'foo',
|
||||||
];
|
];
|
||||||
|
|
||||||
$example3 = ',,,foo,,,';
|
$example3 = ',,,foo,,,';
|
||||||
@ -181,63 +214,86 @@ class LexerTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testLexesStrings() : void
|
public function testLexesStrings() : void
|
||||||
{
|
{
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::STRING,
|
'kind' => Token::STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 8,
|
'end' => 8,
|
||||||
'value' => 'simple'
|
'value' => 'simple',
|
||||||
], (array) $this->lexOne('"simple"'));
|
],
|
||||||
|
(array) $this->lexOne('"simple"')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertArraySubset(
|
||||||
$this->assertArraySubset([
|
[
|
||||||
'kind' => Token::STRING,
|
'kind' => Token::STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 15,
|
'end' => 15,
|
||||||
'value' => ' white space '
|
'value' => ' white space ',
|
||||||
], (array) $this->lexOne('" white space "'));
|
],
|
||||||
|
(array) $this->lexOne('" white space "')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::STRING,
|
'kind' => Token::STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 10,
|
'end' => 10,
|
||||||
'value' => 'quote "'
|
'value' => 'quote "',
|
||||||
], (array) $this->lexOne('"quote \\""'));
|
],
|
||||||
|
(array) $this->lexOne('"quote \\""')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::STRING,
|
'kind' => Token::STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 25,
|
'end' => 25,
|
||||||
'value' => 'escaped \n\r\b\t\f'
|
'value' => 'escaped \n\r\b\t\f',
|
||||||
], (array) $this->lexOne('"escaped \\\\n\\\\r\\\\b\\\\t\\\\f"'));
|
],
|
||||||
|
(array) $this->lexOne('"escaped \\\\n\\\\r\\\\b\\\\t\\\\f"')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::STRING,
|
'kind' => Token::STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 16,
|
'end' => 16,
|
||||||
'value' => 'slashes \\ \/'
|
'value' => 'slashes \\ \/',
|
||||||
], (array) $this->lexOne('"slashes \\\\ \\\\/"'));
|
],
|
||||||
|
(array) $this->lexOne('"slashes \\\\ \\\\/"')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::STRING,
|
'kind' => Token::STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 13,
|
'end' => 13,
|
||||||
'value' => 'unicode яуц'
|
'value' => 'unicode яуц',
|
||||||
], (array) $this->lexOne('"unicode яуц"'));
|
],
|
||||||
|
(array) $this->lexOne('"unicode яуц"')
|
||||||
|
);
|
||||||
|
|
||||||
$unicode = json_decode('"\u1234\u5678\u90AB\uCDEF"');
|
$unicode = json_decode('"\u1234\u5678\u90AB\uCDEF"');
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::STRING,
|
'kind' => Token::STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 34,
|
'end' => 34,
|
||||||
'value' => 'unicode ' . $unicode
|
'value' => 'unicode ' . $unicode,
|
||||||
], (array) $this->lexOne('"unicode \u1234\u5678\u90AB\uCDEF"'));
|
],
|
||||||
|
(array) $this->lexOne('"unicode \u1234\u5678\u90AB\uCDEF"')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::STRING,
|
'kind' => Token::STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 26,
|
'end' => 26,
|
||||||
'value' => $unicode
|
'value' => $unicode,
|
||||||
], (array) $this->lexOne('"\u1234\u5678\u90AB\uCDEF"'));
|
],
|
||||||
|
(array) $this->lexOne('"\u1234\u5678\u90AB\uCDEF"')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,86 +301,128 @@ class LexerTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testLexesBlockString() : void
|
public function testLexesBlockString() : void
|
||||||
{
|
{
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::BLOCK_STRING,
|
'kind' => Token::BLOCK_STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 12,
|
'end' => 12,
|
||||||
'value' => 'simple'
|
'value' => 'simple',
|
||||||
], (array) $this->lexOne('"""simple"""'));
|
],
|
||||||
|
(array) $this->lexOne('"""simple"""')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::BLOCK_STRING,
|
'kind' => Token::BLOCK_STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 19,
|
'end' => 19,
|
||||||
'value' => ' white space '
|
'value' => ' white space ',
|
||||||
], (array) $this->lexOne('""" white space """'));
|
],
|
||||||
|
(array) $this->lexOne('""" white space """')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::BLOCK_STRING,
|
'kind' => Token::BLOCK_STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 22,
|
'end' => 22,
|
||||||
'value' => 'contains " quote'
|
'value' => 'contains " quote',
|
||||||
], (array) $this->lexOne('"""contains " quote"""'));
|
],
|
||||||
|
(array) $this->lexOne('"""contains " quote"""')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::BLOCK_STRING,
|
'kind' => Token::BLOCK_STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 31,
|
'end' => 31,
|
||||||
'value' => 'contains """ triplequote'
|
'value' => 'contains """ triplequote',
|
||||||
], (array) $this->lexOne('"""contains \\""" triplequote"""'));
|
],
|
||||||
|
(array) $this->lexOne('"""contains \\""" triplequote"""')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::BLOCK_STRING,
|
'kind' => Token::BLOCK_STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 16,
|
'end' => 16,
|
||||||
'value' => "multi\nline"
|
'value' => "multi\nline",
|
||||||
], (array) $this->lexOne("\"\"\"multi\nline\"\"\""));
|
],
|
||||||
|
(array) $this->lexOne("\"\"\"multi\nline\"\"\"")
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::BLOCK_STRING,
|
'kind' => Token::BLOCK_STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 28,
|
'end' => 28,
|
||||||
'value' => "multi\nline\nnormalized"
|
'value' => "multi\nline\nnormalized",
|
||||||
], (array) $this->lexOne("\"\"\"multi\rline\r\nnormalized\"\"\""));
|
],
|
||||||
|
(array) $this->lexOne("\"\"\"multi\rline\r\nnormalized\"\"\"")
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::BLOCK_STRING,
|
'kind' => Token::BLOCK_STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 32,
|
'end' => 32,
|
||||||
'value' => 'unescaped \\n\\r\\b\\t\\f\\u1234'
|
'value' => 'unescaped \\n\\r\\b\\t\\f\\u1234',
|
||||||
], (array) $this->lexOne('"""unescaped \\n\\r\\b\\t\\f\\u1234"""'));
|
],
|
||||||
|
(array) $this->lexOne('"""unescaped \\n\\r\\b\\t\\f\\u1234"""')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::BLOCK_STRING,
|
'kind' => Token::BLOCK_STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 19,
|
'end' => 19,
|
||||||
'value' => 'slashes \\\\ \\/'
|
'value' => 'slashes \\\\ \\/',
|
||||||
], (array) $this->lexOne('"""slashes \\\\ \\/"""'));
|
],
|
||||||
|
(array) $this->lexOne('"""slashes \\\\ \\/"""')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'kind' => Token::BLOCK_STRING,
|
'kind' => Token::BLOCK_STRING,
|
||||||
'start' => 0,
|
'start' => 0,
|
||||||
'end' => 68,
|
'end' => 68,
|
||||||
'value' => "spans\n multiple\n lines"
|
'value' => "spans\n multiple\n lines",
|
||||||
], (array) $this->lexOne("\"\"\"
|
],
|
||||||
|
(array) $this->lexOne('"""
|
||||||
|
|
||||||
spans
|
spans
|
||||||
multiple
|
multiple
|
||||||
lines
|
lines
|
||||||
|
|
||||||
\"\"\""));
|
"""')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reportsUsefulStringErrors() {
|
public function reportsUsefulStringErrors()
|
||||||
|
{
|
||||||
return [
|
return [
|
||||||
['"', "Unterminated string.", $this->loc(1, 2)],
|
['"', 'Unterminated string.', $this->loc(1, 2)],
|
||||||
['"no end quote', "Unterminated string.", $this->loc(1, 14)],
|
['"no end quote', 'Unterminated string.', $this->loc(1, 14)],
|
||||||
["'single quotes'", "Unexpected single quote character ('), did you mean to use a double quote (\")?", $this->loc(1, 1)],
|
[
|
||||||
['"contains unescaped \u0007 control char"', "Invalid character within String: \"\\u0007\"", $this->loc(1, 21)],
|
"'single quotes'",
|
||||||
|
"Unexpected single quote character ('), did you mean to use a double quote (\")?",
|
||||||
|
$this->loc(
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"contains unescaped \u0007 control char"',
|
||||||
|
"Invalid character within String: \"\\u0007\"",
|
||||||
|
$this->loc(
|
||||||
|
1,
|
||||||
|
21
|
||||||
|
),
|
||||||
|
],
|
||||||
['"null-byte is not \u0000 end of file"', 'Invalid character within String: "\\u0000"', $this->loc(1, 19)],
|
['"null-byte is not \u0000 end of file"', 'Invalid character within String: "\\u0000"', $this->loc(1, 19)],
|
||||||
['"multi' . "\n" . 'line"', "Unterminated string.", $this->loc(1, 7)],
|
['"multi' . "\n" . 'line"', 'Unterminated string.', $this->loc(1, 7)],
|
||||||
['"multi' . "\r" . 'line"', "Unterminated string.", $this->loc(1, 7)],
|
['"multi' . "\r" . 'line"', 'Unterminated string.', $this->loc(1, 7)],
|
||||||
['"bad \\z esc"', "Invalid character escape sequence: \\z", $this->loc(1, 7)],
|
['"bad \\z esc"', 'Invalid character escape sequence: \\z', $this->loc(1, 7)],
|
||||||
['"bad \\x esc"', "Invalid character escape sequence: \\x", $this->loc(1, 7)],
|
['"bad \\x esc"', "Invalid character escape sequence: \\x", $this->loc(1, 7)],
|
||||||
['"bad \\u1 esc"', "Invalid character escape sequence: \\u1 es", $this->loc(1, 7)],
|
['"bad \\u1 esc"', "Invalid character escape sequence: \\u1 es", $this->loc(1, 7)],
|
||||||
['"bad \\u0XX1 esc"', "Invalid character escape sequence: \\u0XX1", $this->loc(1, 7)],
|
['"bad \\u0XX1 esc"', "Invalid character escape sequence: \\u0XX1", $this->loc(1, 7)],
|
||||||
@ -343,12 +441,27 @@ class LexerTest extends TestCase
|
|||||||
$this->expectSyntaxError($str, $expectedMessage, $location);
|
$this->expectSyntaxError($str, $expectedMessage, $location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reportsUsefulBlockStringErrors() {
|
public function reportsUsefulBlockStringErrors()
|
||||||
|
{
|
||||||
return [
|
return [
|
||||||
['"""', "Unterminated string.", $this->loc(1, 4)],
|
['"""', 'Unterminated string.', $this->loc(1, 4)],
|
||||||
['"""no end quote', "Unterminated string.", $this->loc(1, 16)],
|
['"""no end quote', 'Unterminated string.', $this->loc(1, 16)],
|
||||||
['"""contains unescaped ' . json_decode('"\u0007"') . ' control char"""', "Invalid character within String: \"\\u0007\"", $this->loc(1, 23)],
|
[
|
||||||
['"""null-byte is not ' . json_decode('"\u0000"') . ' end of file"""', "Invalid character within String: \"\\u0000\"", $this->loc(1, 21)],
|
'"""contains unescaped ' . json_decode('"\u0007"') . ' control char"""',
|
||||||
|
"Invalid character within String: \"\\u0007\"",
|
||||||
|
$this->loc(
|
||||||
|
1,
|
||||||
|
23
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"""null-byte is not ' . json_decode('"\u0000"') . ' end of file"""',
|
||||||
|
"Invalid character within String: \"\\u0000\"",
|
||||||
|
$this->loc(
|
||||||
|
1,
|
||||||
|
21
|
||||||
|
),
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,15 +548,15 @@ class LexerTest extends TestCase
|
|||||||
public function reportsUsefulNumberErrors()
|
public function reportsUsefulNumberErrors()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
[ '00', "Invalid number, unexpected digit after 0: \"0\"", $this->loc(1, 2)],
|
['00', 'Invalid number, unexpected digit after 0: "0"', $this->loc(1, 2)],
|
||||||
[ '+1', "Cannot parse the unexpected character \"+\".", $this->loc(1, 1)],
|
['+1', 'Cannot parse the unexpected character "+".', $this->loc(1, 1)],
|
||||||
[ '1.', "Invalid number, expected digit but got: <EOF>", $this->loc(1, 3)],
|
['1.', 'Invalid number, expected digit but got: <EOF>', $this->loc(1, 3)],
|
||||||
[ '1.e1', "Invalid number, expected digit but got: \"e\"", $this->loc(1, 3)],
|
['1.e1', 'Invalid number, expected digit but got: "e"', $this->loc(1, 3)],
|
||||||
[ '.123', "Cannot parse the unexpected character \".\".", $this->loc(1, 1)],
|
['.123', 'Cannot parse the unexpected character ".".', $this->loc(1, 1)],
|
||||||
[ '1.A', "Invalid number, expected digit but got: \"A\"", $this->loc(1, 3)],
|
['1.A', 'Invalid number, expected digit but got: "A"', $this->loc(1, 3)],
|
||||||
[ '-A', "Invalid number, expected digit but got: \"A\"", $this->loc(1, 2)],
|
['-A', 'Invalid number, expected digit but got: "A"', $this->loc(1, 2)],
|
||||||
[ '1.0e', "Invalid number, expected digit but got: <EOF>", $this->loc(1, 5)],
|
['1.0e', 'Invalid number, expected digit but got: <EOF>', $this->loc(1, 5)],
|
||||||
[ '1.0eA', "Invalid number, expected digit but got: \"A\"", $this->loc(1, 5)],
|
['1.0eA', 'Invalid number, expected digit but got: "A"', $this->loc(1, 5)],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,8 +634,8 @@ class LexerTest extends TestCase
|
|||||||
$unicode2 = json_decode('"\u200b"');
|
$unicode2 = json_decode('"\u200b"');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
['..', "Cannot parse the unexpected character \".\".", $this->loc(1, 1)],
|
['..', 'Cannot parse the unexpected character ".".', $this->loc(1, 1)],
|
||||||
['?', "Cannot parse the unexpected character \"?\".", $this->loc(1, 1)],
|
['?', 'Cannot parse the unexpected character "?".', $this->loc(1, 1)],
|
||||||
[$unicode1, "Cannot parse the unexpected character \"\\u203b\".", $this->loc(1, 1)],
|
[$unicode1, "Cannot parse the unexpected character \"\\u203b\".", $this->loc(1, 1)],
|
||||||
[$unicode2, "Cannot parse the unexpected character \"\\u200b\".", $this->loc(1, 1)],
|
[$unicode2, "Cannot parse the unexpected character \"\\u200b\".", $this->loc(1, 1)],
|
||||||
];
|
];
|
||||||
@ -544,15 +657,18 @@ class LexerTest extends TestCase
|
|||||||
{
|
{
|
||||||
$q = 'a-b';
|
$q = 'a-b';
|
||||||
$lexer = new Lexer(new Source($q));
|
$lexer = new Lexer(new Source($q));
|
||||||
$this->assertArraySubset(['kind' => Token::NAME, 'start' => 0, 'end' => 1, 'value' => 'a'], (array) $lexer->advance());
|
$this->assertArraySubset(
|
||||||
|
['kind' => Token::NAME, 'start' => 0, 'end' => 1, 'value' => 'a'],
|
||||||
|
(array) $lexer->advance()
|
||||||
|
);
|
||||||
|
|
||||||
$this->expectException(SyntaxError::class);
|
$this->expectException(SyntaxError::class);
|
||||||
$this->expectExceptionMessage('Syntax Error: Invalid number, expected digit but got: "b"');
|
$this->expectExceptionMessage('Syntax Error: Invalid number, expected digit but got: "b"');
|
||||||
try {
|
try {
|
||||||
$lexer->advance();
|
$lexer->advance();
|
||||||
$this->fail('Expected exception not thrown');
|
$this->fail('Expected exception not thrown');
|
||||||
} catch(SyntaxError $error) {
|
} catch (SyntaxError $error) {
|
||||||
$this->assertEquals([$this->loc(1,3)], $error->getLocations());
|
$this->assertEquals([$this->loc(1, 3)], $error->getLocations());
|
||||||
throw $error;
|
throw $error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -580,49 +696,28 @@ class LexerTest extends TestCase
|
|||||||
|
|
||||||
$tokens = [];
|
$tokens = [];
|
||||||
for ($tok = $startToken; $tok; $tok = $tok->next) {
|
for ($tok = $startToken; $tok; $tok = $tok->next) {
|
||||||
if (!empty($tokens)) {
|
if (! empty($tokens)) {
|
||||||
// Tokens are double-linked, prev should point to last seen token.
|
// Tokens are double-linked, prev should point to last seen token.
|
||||||
$this->assertSame($tokens[count($tokens) - 1], $tok->prev);
|
$this->assertSame($tokens[count($tokens) - 1], $tok->prev);
|
||||||
}
|
}
|
||||||
$tokens[] = $tok;
|
$tokens[] = $tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'<SOF>',
|
'<SOF>',
|
||||||
'{',
|
'{',
|
||||||
'Comment',
|
'Comment',
|
||||||
'Name',
|
'Name',
|
||||||
'}',
|
'}',
|
||||||
'<EOF>'
|
'<EOF>',
|
||||||
], Utils::map($tokens, function ($tok) {
|
],
|
||||||
|
Utils::map(
|
||||||
|
$tokens,
|
||||||
|
function ($tok) {
|
||||||
return $tok->kind;
|
return $tok->kind;
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $body
|
|
||||||
* @return Token
|
|
||||||
*/
|
|
||||||
private function lexOne($body)
|
|
||||||
{
|
|
||||||
$lexer = new Lexer(new Source($body));
|
|
||||||
return $lexer->advance();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function loc($line, $column)
|
|
||||||
{
|
|
||||||
return new SourceLocation($line, $column);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function expectSyntaxError($text, $message, $location)
|
|
||||||
{
|
|
||||||
$this->expectException(SyntaxError::class);
|
|
||||||
$this->expectExceptionMessage($message);
|
|
||||||
try {
|
|
||||||
$this->lexOne($text);
|
|
||||||
} catch (SyntaxError $error) {
|
|
||||||
$this->assertEquals([$location], $error->getLocations());
|
|
||||||
throw $error;
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Language;
|
namespace GraphQL\Tests\Language;
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
|
use GraphQL\Error\SyntaxError;
|
||||||
use GraphQL\Language\AST\ArgumentNode;
|
use GraphQL\Language\AST\ArgumentNode;
|
||||||
use GraphQL\Language\AST\FieldNode;
|
use GraphQL\Language\AST\FieldNode;
|
||||||
use GraphQL\Language\AST\NameNode;
|
use GraphQL\Language\AST\NameNode;
|
||||||
@ -13,9 +17,10 @@ use GraphQL\Language\AST\StringValueNode;
|
|||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\Source;
|
use GraphQL\Language\Source;
|
||||||
use GraphQL\Language\SourceLocation;
|
use GraphQL\Language\SourceLocation;
|
||||||
use GraphQL\Error\SyntaxError;
|
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function file_get_contents;
|
||||||
|
use function sprintf;
|
||||||
|
|
||||||
class ParserTest extends TestCase
|
class ParserTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -43,13 +48,26 @@ class ParserTest extends TestCase
|
|||||||
public function parseProvidesUsefulErrors()
|
public function parseProvidesUsefulErrors()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
['{', "Syntax Error: Expected Name, found <EOF>", "Syntax Error: Expected Name, found <EOF>\n\nGraphQL request (1:2)\n1: {\n ^\n", [1], [new SourceLocation(1, 2)]],
|
[
|
||||||
['{ ...MissingOn }
|
'{',
|
||||||
|
'Syntax Error: Expected Name, found <EOF>',
|
||||||
|
"Syntax Error: Expected Name, found <EOF>\n\nGraphQL request (1:2)\n1: {\n ^\n",
|
||||||
|
[1],
|
||||||
|
[new SourceLocation(
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'{ ...MissingOn }
|
||||||
fragment MissingOn Type
|
fragment MissingOn Type
|
||||||
', "Syntax Error: Expected \"on\", found Name \"Type\"", "Syntax Error: Expected \"on\", found Name \"Type\"\n\nGraphQL request (2:20)\n1: { ...MissingOn }\n2: fragment MissingOn Type\n ^\n3: \n",],
|
', 'Syntax Error: Expected "on", found Name "Type"',
|
||||||
['{ field: {} }', "Syntax Error: Expected Name, found {", "Syntax Error: Expected Name, found {\n\nGraphQL request (1:10)\n1: { field: {} }\n ^\n"],
|
"Syntax Error: Expected \"on\", found Name \"Type\"\n\nGraphQL request (2:20)\n1: { ...MissingOn }\n2: fragment MissingOn Type\n ^\n3: \n",
|
||||||
['notanoperation Foo { field }', "Syntax Error: Unexpected Name \"notanoperation\"", "Syntax Error: Unexpected Name \"notanoperation\"\n\nGraphQL request (1:1)\n1: notanoperation Foo { field }\n ^\n"],
|
],
|
||||||
['...', "Syntax Error: Unexpected ...", "Syntax Error: Unexpected ...\n\nGraphQL request (1:1)\n1: ...\n ^\n"],
|
['{ field: {} }', 'Syntax Error: Expected Name, found {', "Syntax Error: Expected Name, found {\n\nGraphQL request (1:10)\n1: { field: {} }\n ^\n"],
|
||||||
|
['notanoperation Foo { field }', 'Syntax Error: Unexpected Name "notanoperation"', "Syntax Error: Unexpected Name \"notanoperation\"\n\nGraphQL request (1:1)\n1: notanoperation Foo { field }\n ^\n"],
|
||||||
|
['...', 'Syntax Error: Unexpected ...', "Syntax Error: Unexpected ...\n\nGraphQL request (1:1)\n1: ...\n ^\n"],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,8 +75,13 @@ fragment MissingOn Type
|
|||||||
* @dataProvider parseProvidesUsefulErrors
|
* @dataProvider parseProvidesUsefulErrors
|
||||||
* @see it('parse provides useful errors')
|
* @see it('parse provides useful errors')
|
||||||
*/
|
*/
|
||||||
public function testParseProvidesUsefulErrors($str, $expectedMessage, $stringRepresentation, $expectedPositions = null, $expectedLocations = null) : void
|
public function testParseProvidesUsefulErrors(
|
||||||
{
|
$str,
|
||||||
|
$expectedMessage,
|
||||||
|
$stringRepresentation,
|
||||||
|
$expectedPositions = null,
|
||||||
|
$expectedLocations = null
|
||||||
|
) : void {
|
||||||
try {
|
try {
|
||||||
Parser::parse($str);
|
Parser::parse($str);
|
||||||
$this->fail('Expected exception not thrown');
|
$this->fail('Expected exception not thrown');
|
||||||
@ -110,10 +133,27 @@ fragment MissingOn Type
|
|||||||
$this->expectSyntaxError(
|
$this->expectSyntaxError(
|
||||||
'query Foo($x: Complex = { a: { b: [ $var ] } }) { field }',
|
'query Foo($x: Complex = { a: { b: [ $var ] } }) { field }',
|
||||||
'Unexpected $',
|
'Unexpected $',
|
||||||
$this->loc(1,37)
|
$this->loc(1, 37)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function expectSyntaxError($text, $message, $location)
|
||||||
|
{
|
||||||
|
$this->expectException(SyntaxError::class);
|
||||||
|
$this->expectExceptionMessage($message);
|
||||||
|
try {
|
||||||
|
Parser::parse($text);
|
||||||
|
} catch (SyntaxError $error) {
|
||||||
|
$this->assertEquals([$location], $error->getLocations());
|
||||||
|
throw $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loc($line, $column)
|
||||||
|
{
|
||||||
|
return new SourceLocation($line, $column);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('does not accept fragments spread of "on"')
|
* @see it('does not accept fragments spread of "on"')
|
||||||
*/
|
*/
|
||||||
@ -122,7 +162,7 @@ fragment MissingOn Type
|
|||||||
$this->expectSyntaxError(
|
$this->expectSyntaxError(
|
||||||
'fragment on on on { on }',
|
'fragment on on on { on }',
|
||||||
'Unexpected Name "on"',
|
'Unexpected Name "on"',
|
||||||
$this->loc(1,10)
|
$this->loc(1, 10)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +174,7 @@ fragment MissingOn Type
|
|||||||
$this->expectSyntaxError(
|
$this->expectSyntaxError(
|
||||||
'{ ...on }',
|
'{ ...on }',
|
||||||
'Expected Name, found }',
|
'Expected Name, found }',
|
||||||
$this->loc(1,9)
|
$this->loc(1, 9)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,14 +200,14 @@ HEREDOC;
|
|||||||
'arguments' => new NodeList([
|
'arguments' => new NodeList([
|
||||||
new ArgumentNode([
|
new ArgumentNode([
|
||||||
'name' => new NameNode(['value' => 'arg']),
|
'name' => new NameNode(['value' => 'arg']),
|
||||||
'value' => new StringValueNode([
|
'value' => new StringValueNode(
|
||||||
'value' => "Has a $char multi-byte character."
|
['value' => sprintf('Has a %s multi-byte character.', $char)]
|
||||||
])
|
),
|
||||||
])
|
]),
|
||||||
|
]),
|
||||||
|
'directives' => new NodeList([]),
|
||||||
|
]),
|
||||||
]),
|
]),
|
||||||
'directives' => new NodeList([])
|
|
||||||
])
|
|
||||||
])
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->definitions[0]->selectionSet);
|
$this->assertEquals($expected, $result->definitions[0]->selectionSet);
|
||||||
@ -196,7 +236,7 @@ HEREDOC;
|
|||||||
'mutation',
|
'mutation',
|
||||||
'subscription',
|
'subscription',
|
||||||
'true',
|
'true',
|
||||||
'false'
|
'false',
|
||||||
];
|
];
|
||||||
foreach ($nonKeywords as $keyword) {
|
foreach ($nonKeywords as $keyword) {
|
||||||
$fragmentName = $keyword;
|
$fragmentName = $keyword;
|
||||||
@ -205,14 +245,19 @@ HEREDOC;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Expected not to throw:
|
// Expected not to throw:
|
||||||
$result = Parser::parse("query $keyword {
|
$result = Parser::parse(<<<GRAPHQL
|
||||||
... $fragmentName
|
query $keyword {
|
||||||
... on $keyword { field }
|
... $fragmentName
|
||||||
|
... on $keyword { field }
|
||||||
|
}
|
||||||
|
fragment $fragmentName on Type {
|
||||||
|
$keyword($keyword: \$$keyword) @$keyword($keyword: $keyword)
|
||||||
}
|
}
|
||||||
fragment $fragmentName on Type {
|
fragment $fragmentName on Type {
|
||||||
$keyword($keyword: \$$keyword) @$keyword($keyword: $keyword)
|
$keyword($keyword: \$$keyword) @$keyword($keyword: $keyword)
|
||||||
}
|
}
|
||||||
");
|
GRAPHQL
|
||||||
|
);
|
||||||
$this->assertNotEmpty($result);
|
$this->assertNotEmpty($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,10 +331,10 @@ fragment $fragmentName on Type {
|
|||||||
');
|
');
|
||||||
$result = Parser::parse($source);
|
$result = Parser::parse($source);
|
||||||
|
|
||||||
$loc = function($start, $end) use ($source) {
|
$loc = function ($start, $end) {
|
||||||
return [
|
return [
|
||||||
'start' => $start,
|
'start' => $start,
|
||||||
'end' => $end
|
'end' => $end,
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -315,7 +360,7 @@ fragment $fragmentName on Type {
|
|||||||
'name' => [
|
'name' => [
|
||||||
'kind' => NodeKind::NAME,
|
'kind' => NodeKind::NAME,
|
||||||
'loc' => $loc(4, 8),
|
'loc' => $loc(4, 8),
|
||||||
'value' => 'node'
|
'value' => 'node',
|
||||||
],
|
],
|
||||||
'arguments' => [
|
'arguments' => [
|
||||||
[
|
[
|
||||||
@ -323,15 +368,15 @@ fragment $fragmentName on Type {
|
|||||||
'name' => [
|
'name' => [
|
||||||
'kind' => NodeKind::NAME,
|
'kind' => NodeKind::NAME,
|
||||||
'loc' => $loc(9, 11),
|
'loc' => $loc(9, 11),
|
||||||
'value' => 'id'
|
'value' => 'id',
|
||||||
],
|
],
|
||||||
'value' => [
|
'value' => [
|
||||||
'kind' => NodeKind::INT,
|
'kind' => NodeKind::INT,
|
||||||
'loc' => $loc(13, 14),
|
'loc' => $loc(13, 14),
|
||||||
'value' => '4'
|
'value' => '4',
|
||||||
|
],
|
||||||
|
'loc' => $loc(9, 14, $source),
|
||||||
],
|
],
|
||||||
'loc' => $loc(9, 14, $source)
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'directives' => [],
|
'directives' => [],
|
||||||
'selectionSet' => [
|
'selectionSet' => [
|
||||||
@ -345,11 +390,11 @@ fragment $fragmentName on Type {
|
|||||||
'name' => [
|
'name' => [
|
||||||
'kind' => NodeKind::NAME,
|
'kind' => NodeKind::NAME,
|
||||||
'loc' => $loc(22, 24),
|
'loc' => $loc(22, 24),
|
||||||
'value' => 'id'
|
'value' => 'id',
|
||||||
],
|
],
|
||||||
'arguments' => [],
|
'arguments' => [],
|
||||||
'directives' => [],
|
'directives' => [],
|
||||||
'selectionSet' => null
|
'selectionSet' => null,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'kind' => NodeKind::FIELD,
|
'kind' => NodeKind::FIELD,
|
||||||
@ -358,22 +403,30 @@ fragment $fragmentName on Type {
|
|||||||
'name' => [
|
'name' => [
|
||||||
'kind' => NodeKind::NAME,
|
'kind' => NodeKind::NAME,
|
||||||
'loc' => $loc(30, 34),
|
'loc' => $loc(30, 34),
|
||||||
'value' => 'name'
|
'value' => 'name',
|
||||||
],
|
],
|
||||||
'arguments' => [],
|
'arguments' => [],
|
||||||
'directives' => [],
|
'directives' => [],
|
||||||
'selectionSet' => null
|
'selectionSet' => null,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $this->nodeToArray($result));
|
$this->assertEquals($expected, self::nodeToArray($result));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
public static function nodeToArray(Node $node) : array
|
||||||
|
{
|
||||||
|
return TestUtils::nodeToArray($node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -389,10 +442,10 @@ fragment $fragmentName on Type {
|
|||||||
');
|
');
|
||||||
$result = Parser::parse($source);
|
$result = Parser::parse($source);
|
||||||
|
|
||||||
$loc = function($start, $end) use ($source) {
|
$loc = function ($start, $end) {
|
||||||
return [
|
return [
|
||||||
'start' => $start,
|
'start' => $start,
|
||||||
'end' => $end
|
'end' => $end,
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -418,7 +471,7 @@ fragment $fragmentName on Type {
|
|||||||
'name' => [
|
'name' => [
|
||||||
'kind' => NodeKind::NAME,
|
'kind' => NodeKind::NAME,
|
||||||
'loc' => $loc(10, 14),
|
'loc' => $loc(10, 14),
|
||||||
'value' => 'node'
|
'value' => 'node',
|
||||||
],
|
],
|
||||||
'arguments' => [],
|
'arguments' => [],
|
||||||
'directives' => [],
|
'directives' => [],
|
||||||
@ -433,19 +486,19 @@ fragment $fragmentName on Type {
|
|||||||
'name' => [
|
'name' => [
|
||||||
'kind' => NodeKind::NAME,
|
'kind' => NodeKind::NAME,
|
||||||
'loc' => $loc(21, 23),
|
'loc' => $loc(21, 23),
|
||||||
'value' => 'id'
|
'value' => 'id',
|
||||||
],
|
],
|
||||||
'arguments' => [],
|
'arguments' => [],
|
||||||
'directives' => [],
|
'directives' => [],
|
||||||
'selectionSet' => null
|
'selectionSet' => null,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $this->nodeToArray($result));
|
$this->assertEquals($expected, $this->nodeToArray($result));
|
||||||
@ -475,6 +528,8 @@ fragment $fragmentName on Type {
|
|||||||
Parser::parse($source);
|
Parser::parse($source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe: parseValue
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('contains location information that only stringifys start/end')
|
* @see it('contains location information that only stringifys start/end')
|
||||||
*/
|
*/
|
||||||
@ -495,6 +550,8 @@ fragment $fragmentName on Type {
|
|||||||
$this->assertEquals($source, $result->loc->source);
|
$this->assertEquals($source, $result->loc->source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe: parseType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('contains references to start and end tokens')
|
* @see it('contains references to start and end tokens')
|
||||||
*/
|
*/
|
||||||
@ -506,17 +563,18 @@ fragment $fragmentName on Type {
|
|||||||
$this->assertEquals('<EOF>', $result->loc->endToken->kind);
|
$this->assertEquals('<EOF>', $result->loc->endToken->kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: parseValue
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('parses null value')
|
* @see it('parses null value')
|
||||||
*/
|
*/
|
||||||
public function testParsesNullValues() : void
|
public function testParsesNullValues() : void
|
||||||
{
|
{
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'kind' => NodeKind::NULL,
|
'kind' => NodeKind::NULL,
|
||||||
'loc' => ['start' => 0, 'end' => 4]
|
'loc' => ['start' => 0, 'end' => 4],
|
||||||
], $this->nodeToArray(Parser::parseValue('null')));
|
],
|
||||||
|
$this->nodeToArray(Parser::parseValue('null'))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -524,41 +582,45 @@ fragment $fragmentName on Type {
|
|||||||
*/
|
*/
|
||||||
public function testParsesListValues() : void
|
public function testParsesListValues() : void
|
||||||
{
|
{
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'kind' => NodeKind::LST,
|
'kind' => NodeKind::LST,
|
||||||
'loc' => ['start' => 0, 'end' => 11],
|
'loc' => ['start' => 0, 'end' => 11],
|
||||||
'values' => [
|
'values' => [
|
||||||
[
|
[
|
||||||
'kind' => NodeKind::INT,
|
'kind' => NodeKind::INT,
|
||||||
'loc' => ['start' => 1, 'end' => 4],
|
'loc' => ['start' => 1, 'end' => 4],
|
||||||
'value' => '123'
|
'value' => '123',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'kind' => NodeKind::STRING,
|
'kind' => NodeKind::STRING,
|
||||||
'loc' => ['start' => 5, 'end' => 10],
|
'loc' => ['start' => 5, 'end' => 10],
|
||||||
'value' => 'abc',
|
'value' => 'abc',
|
||||||
'block' => false
|
'block' => false,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
], $this->nodeToArray(Parser::parseValue('[123 "abc"]')));
|
],
|
||||||
|
$this->nodeToArray(Parser::parseValue('[123 "abc"]'))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: parseType
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('parses well known types')
|
* @see it('parses well known types')
|
||||||
*/
|
*/
|
||||||
public function testParsesWellKnownTypes() : void
|
public function testParsesWellKnownTypes() : void
|
||||||
{
|
{
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'kind' => NodeKind::NAMED_TYPE,
|
'kind' => NodeKind::NAMED_TYPE,
|
||||||
'loc' => ['start' => 0, 'end' => 6],
|
'loc' => ['start' => 0, 'end' => 6],
|
||||||
'name' => [
|
'name' => [
|
||||||
'kind' => NodeKind::NAME,
|
'kind' => NodeKind::NAME,
|
||||||
'loc' => ['start' => 0, 'end' => 6],
|
'loc' => ['start' => 0, 'end' => 6],
|
||||||
'value' => 'String'
|
'value' => 'String',
|
||||||
]
|
],
|
||||||
], $this->nodeToArray(Parser::parseType('String')));
|
],
|
||||||
|
$this->nodeToArray(Parser::parseType('String'))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -566,15 +628,18 @@ fragment $fragmentName on Type {
|
|||||||
*/
|
*/
|
||||||
public function testParsesCustomTypes() : void
|
public function testParsesCustomTypes() : void
|
||||||
{
|
{
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'kind' => NodeKind::NAMED_TYPE,
|
'kind' => NodeKind::NAMED_TYPE,
|
||||||
'loc' => ['start' => 0, 'end' => 6],
|
'loc' => ['start' => 0, 'end' => 6],
|
||||||
'name' => [
|
'name' => [
|
||||||
'kind' => NodeKind::NAME,
|
'kind' => NodeKind::NAME,
|
||||||
'loc' => ['start' => 0, 'end' => 6],
|
'loc' => ['start' => 0, 'end' => 6],
|
||||||
'value' => 'MyType'
|
'value' => 'MyType',
|
||||||
]
|
],
|
||||||
], $this->nodeToArray(Parser::parseType('MyType')));
|
],
|
||||||
|
$this->nodeToArray(Parser::parseType('MyType'))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -582,7 +647,8 @@ fragment $fragmentName on Type {
|
|||||||
*/
|
*/
|
||||||
public function testParsesListTypes() : void
|
public function testParsesListTypes() : void
|
||||||
{
|
{
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'kind' => NodeKind::LIST_TYPE,
|
'kind' => NodeKind::LIST_TYPE,
|
||||||
'loc' => ['start' => 0, 'end' => 8],
|
'loc' => ['start' => 0, 'end' => 8],
|
||||||
'type' => [
|
'type' => [
|
||||||
@ -591,10 +657,12 @@ fragment $fragmentName on Type {
|
|||||||
'name' => [
|
'name' => [
|
||||||
'kind' => NodeKind::NAME,
|
'kind' => NodeKind::NAME,
|
||||||
'loc' => ['start' => 1, 'end' => 7],
|
'loc' => ['start' => 1, 'end' => 7],
|
||||||
'value' => 'MyType'
|
'value' => 'MyType',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
], $this->nodeToArray(Parser::parseType('[MyType]')));
|
],
|
||||||
|
$this->nodeToArray(Parser::parseType('[MyType]'))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -602,7 +670,8 @@ fragment $fragmentName on Type {
|
|||||||
*/
|
*/
|
||||||
public function testParsesNonNullTypes() : void
|
public function testParsesNonNullTypes() : void
|
||||||
{
|
{
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'kind' => NodeKind::NON_NULL_TYPE,
|
'kind' => NodeKind::NON_NULL_TYPE,
|
||||||
'loc' => ['start' => 0, 'end' => 7],
|
'loc' => ['start' => 0, 'end' => 7],
|
||||||
'type' => [
|
'type' => [
|
||||||
@ -611,10 +680,12 @@ fragment $fragmentName on Type {
|
|||||||
'name' => [
|
'name' => [
|
||||||
'kind' => NodeKind::NAME,
|
'kind' => NodeKind::NAME,
|
||||||
'loc' => ['start' => 0, 'end' => 6],
|
'loc' => ['start' => 0, 'end' => 6],
|
||||||
'value' => 'MyType'
|
'value' => 'MyType',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
], $this->nodeToArray(Parser::parseType('MyType!')));
|
],
|
||||||
|
$this->nodeToArray(Parser::parseType('MyType!'))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -622,7 +693,8 @@ fragment $fragmentName on Type {
|
|||||||
*/
|
*/
|
||||||
public function testParsesNestedTypes() : void
|
public function testParsesNestedTypes() : void
|
||||||
{
|
{
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'kind' => NodeKind::LIST_TYPE,
|
'kind' => NodeKind::LIST_TYPE,
|
||||||
'loc' => ['start' => 0, 'end' => 9],
|
'loc' => ['start' => 0, 'end' => 9],
|
||||||
'type' => [
|
'type' => [
|
||||||
@ -634,36 +706,12 @@ fragment $fragmentName on Type {
|
|||||||
'name' => [
|
'name' => [
|
||||||
'kind' => NodeKind::NAME,
|
'kind' => NodeKind::NAME,
|
||||||
'loc' => ['start' => 1, 'end' => 7],
|
'loc' => ['start' => 1, 'end' => 7],
|
||||||
'value' => 'MyType'
|
'value' => 'MyType',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
], $this->nodeToArray(Parser::parseType('[MyType!]')));
|
],
|
||||||
}
|
$this->nodeToArray(Parser::parseType('[MyType!]'))
|
||||||
|
);
|
||||||
/**
|
|
||||||
* @param Node $node
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function nodeToArray(Node $node)
|
|
||||||
{
|
|
||||||
return TestUtils::nodeToArray($node);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function loc($line, $column)
|
|
||||||
{
|
|
||||||
return new SourceLocation($line, $column);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function expectSyntaxError($text, $message, $location)
|
|
||||||
{
|
|
||||||
$this->expectException(SyntaxError::class);
|
|
||||||
$this->expectExceptionMessage($message);
|
|
||||||
try {
|
|
||||||
Parser::parse($text);
|
|
||||||
} catch (SyntaxError $error) {
|
|
||||||
$this->assertEquals([$location], $error->getLocations());
|
|
||||||
throw $error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Language;
|
namespace GraphQL\Tests\Language;
|
||||||
|
|
||||||
use GraphQL\Language\AST\DocumentNode;
|
|
||||||
use GraphQL\Language\AST\EnumValueNode;
|
|
||||||
use GraphQL\Language\AST\FieldNode;
|
use GraphQL\Language\AST\FieldNode;
|
||||||
use GraphQL\Language\AST\NameNode;
|
use GraphQL\Language\AST\NameNode;
|
||||||
use GraphQL\Language\AST\OperationDefinitionNode;
|
|
||||||
use GraphQL\Language\AST\SelectionSetNode;
|
|
||||||
use GraphQL\Language\AST\StringValueNode;
|
|
||||||
use GraphQL\Language\AST\VariableNode;
|
|
||||||
use GraphQL\Language\AST\VariableDefinitionNode;
|
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\Printer;
|
use GraphQL\Language\Printer;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function file_get_contents;
|
||||||
|
|
||||||
class PrinterTest extends TestCase
|
class PrinterTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -160,7 +157,8 @@ END;
|
|||||||
*/
|
*/
|
||||||
public function testExperimentalCorrectlyPrintsFragmentDefinedVariables() : void
|
public function testExperimentalCorrectlyPrintsFragmentDefinedVariables() : void
|
||||||
{
|
{
|
||||||
$fragmentWithVariable = Parser::parse('
|
$fragmentWithVariable = Parser::parse(
|
||||||
|
'
|
||||||
fragment Foo($a: ComplexType, $b: Boolean = false) on TestType {
|
fragment Foo($a: ComplexType, $b: Boolean = false) on TestType {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Language;
|
namespace GraphQL\Tests\Language;
|
||||||
|
|
||||||
use GraphQL\Error\SyntaxError;
|
use GraphQL\Error\SyntaxError;
|
||||||
@ -10,7 +13,6 @@ use PHPUnit\Framework\TestCase;
|
|||||||
class SchemaParserTest extends TestCase
|
class SchemaParserTest extends TestCase
|
||||||
{
|
{
|
||||||
// Describe: Schema Parser
|
// Describe: Schema Parser
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Simple type')
|
* @see it('Simple type')
|
||||||
*/
|
*/
|
||||||
@ -21,7 +23,9 @@ type Hello {
|
|||||||
world: String
|
world: String
|
||||||
}';
|
}';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -36,17 +40,53 @@ type Hello {
|
|||||||
$this->nameNode('world', $loc(16, 21)),
|
$this->nameNode('world', $loc(16, 21)),
|
||||||
$this->typeNode('String', $loc(23, 29)),
|
$this->typeNode('String', $loc(23, 29)),
|
||||||
$loc(16, 29)
|
$loc(16, 29)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(1, 31),
|
'loc' => $loc(1, 31),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 31)
|
],
|
||||||
|
'loc' => $loc(0, 31),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function nameNode($name, $loc)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'kind' => NodeKind::NAME,
|
||||||
|
'value' => $name,
|
||||||
|
'loc' => $loc,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fieldNode($name, $type, $loc)
|
||||||
|
{
|
||||||
|
return $this->fieldNodeWithArgs($name, $type, [], $loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fieldNodeWithArgs($name, $type, $args, $loc)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'kind' => NodeKind::FIELD_DEFINITION,
|
||||||
|
'name' => $name,
|
||||||
|
'arguments' => $args,
|
||||||
|
'type' => $type,
|
||||||
|
'directives' => [],
|
||||||
|
'loc' => $loc,
|
||||||
|
'description' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function typeNode($name, $loc)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'kind' => NodeKind::NAMED_TYPE,
|
||||||
|
'name' => ['kind' => NodeKind::NAME, 'value' => $name, 'loc' => $loc],
|
||||||
|
'loc' => $loc,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('parses type with description string')
|
* @see it('parses type with description string')
|
||||||
*/
|
*/
|
||||||
@ -58,7 +98,9 @@ type Hello {
|
|||||||
world: String
|
world: String
|
||||||
}';
|
}';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -73,18 +115,18 @@ type Hello {
|
|||||||
$this->nameNode('world', $loc(30, 35)),
|
$this->nameNode('world', $loc(30, 35)),
|
||||||
$this->typeNode('String', $loc(37, 43)),
|
$this->typeNode('String', $loc(37, 43)),
|
||||||
$loc(30, 43)
|
$loc(30, 43)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(1, 45),
|
'loc' => $loc(1, 45),
|
||||||
'description' => [
|
'description' => [
|
||||||
'kind' => NodeKind::STRING,
|
'kind' => NodeKind::STRING,
|
||||||
'value' => 'Description',
|
'value' => 'Description',
|
||||||
'loc' => $loc(1, 14),
|
'loc' => $loc(1, 14),
|
||||||
'block' => false
|
'block' => false,
|
||||||
]
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 45)
|
],
|
||||||
|
],
|
||||||
|
'loc' => $loc(0, 45),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
@ -103,7 +145,9 @@ type Hello {
|
|||||||
world: String
|
world: String
|
||||||
}';
|
}';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -118,18 +162,18 @@ type Hello {
|
|||||||
$this->nameNode('world', $loc(70, 75)),
|
$this->nameNode('world', $loc(70, 75)),
|
||||||
$this->typeNode('String', $loc(77, 83)),
|
$this->typeNode('String', $loc(77, 83)),
|
||||||
$loc(70, 83)
|
$loc(70, 83)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(1, 85),
|
'loc' => $loc(1, 85),
|
||||||
'description' => [
|
'description' => [
|
||||||
'kind' => NodeKind::STRING,
|
'kind' => NodeKind::STRING,
|
||||||
'value' => 'Description',
|
'value' => 'Description',
|
||||||
'loc' => $loc(1, 20),
|
'loc' => $loc(1, 20),
|
||||||
'block' => true
|
'block' => true,
|
||||||
]
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 85)
|
],
|
||||||
|
],
|
||||||
|
'loc' => $loc(0, 85),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
@ -145,9 +189,10 @@ extend type Hello {
|
|||||||
}
|
}
|
||||||
';
|
';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {
|
$loc = function ($start, $end) {
|
||||||
return TestUtils::locArray($start, $end);
|
return TestUtils::locArray($start, $end);
|
||||||
};
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
'definitions' => [
|
'definitions' => [
|
||||||
@ -161,12 +206,12 @@ extend type Hello {
|
|||||||
$this->nameNode('world', $loc(23, 28)),
|
$this->nameNode('world', $loc(23, 28)),
|
||||||
$this->typeNode('String', $loc(30, 36)),
|
$this->typeNode('String', $loc(30, 36)),
|
||||||
$loc(23, 36)
|
$loc(23, 36)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(1, 38)
|
'loc' => $loc(1, 38),
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 39)
|
],
|
||||||
|
'loc' => $loc(0, 39),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
@ -178,9 +223,10 @@ extend type Hello {
|
|||||||
{
|
{
|
||||||
$body = 'extend type Hello implements Greeting';
|
$body = 'extend type Hello implements Greeting';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {
|
$loc = function ($start, $end) {
|
||||||
return TestUtils::locArray($start, $end);
|
return TestUtils::locArray($start, $end);
|
||||||
};
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
'definitions' => [
|
'definitions' => [
|
||||||
@ -192,10 +238,10 @@ extend type Hello {
|
|||||||
],
|
],
|
||||||
'directives' => [],
|
'directives' => [],
|
||||||
'fields' => [],
|
'fields' => [],
|
||||||
'loc' => $loc(0, 37)
|
'loc' => $loc(0, 37),
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 37)
|
],
|
||||||
|
'loc' => $loc(0, 37),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
@ -248,6 +294,23 @@ extend type Hello {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function expectSyntaxError($text, $message, $location)
|
||||||
|
{
|
||||||
|
$this->expectException(SyntaxError::class);
|
||||||
|
$this->expectExceptionMessage($message);
|
||||||
|
try {
|
||||||
|
Parser::parse($text);
|
||||||
|
} catch (SyntaxError $error) {
|
||||||
|
$this->assertEquals([$location], $error->getLocations());
|
||||||
|
throw $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loc($line, $column)
|
||||||
|
{
|
||||||
|
return new SourceLocation($line, $column);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Extension do not include descriptions')
|
* @see it('Extension do not include descriptions')
|
||||||
*/
|
*/
|
||||||
@ -291,17 +354,18 @@ extend type Hello {
|
|||||||
type Hello {
|
type Hello {
|
||||||
world: String!
|
world: String!
|
||||||
}';
|
}';
|
||||||
$loc = function($start, $end) {
|
$doc = Parser::parse($body);
|
||||||
|
|
||||||
|
$loc = function ($start, $end) {
|
||||||
return TestUtils::locArray($start, $end);
|
return TestUtils::locArray($start, $end);
|
||||||
};
|
};
|
||||||
$doc = Parser::parse($body);
|
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
'definitions' => [
|
'definitions' => [
|
||||||
[
|
[
|
||||||
'kind' => NodeKind::OBJECT_TYPE_DEFINITION,
|
'kind' => NodeKind::OBJECT_TYPE_DEFINITION,
|
||||||
'name' => $this->nameNode('Hello', $loc(6,11)),
|
'name' => $this->nameNode('Hello', $loc(6, 11)),
|
||||||
'interfaces' => [],
|
'interfaces' => [],
|
||||||
'directives' => [],
|
'directives' => [],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
@ -310,16 +374,16 @@ type Hello {
|
|||||||
[
|
[
|
||||||
'kind' => NodeKind::NON_NULL_TYPE,
|
'kind' => NodeKind::NON_NULL_TYPE,
|
||||||
'type' => $this->typeNode('String', $loc(23, 29)),
|
'type' => $this->typeNode('String', $loc(23, 29)),
|
||||||
'loc' => $loc(23, 30)
|
'loc' => $loc(23, 30),
|
||||||
],
|
],
|
||||||
$loc(16,30)
|
$loc(16, 30)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(1,32),
|
'loc' => $loc(1, 32),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0,32)
|
],
|
||||||
|
'loc' => $loc(0, 32),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
@ -331,8 +395,10 @@ type Hello {
|
|||||||
public function testSimpleTypeInheritingInterface() : void
|
public function testSimpleTypeInheritingInterface() : void
|
||||||
{
|
{
|
||||||
$body = 'type Hello implements World { field: String }';
|
$body = 'type Hello implements World { field: String }';
|
||||||
$loc = function($start, $end) { return TestUtils::locArray($start, $end); };
|
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -341,7 +407,7 @@ type Hello {
|
|||||||
'kind' => NodeKind::OBJECT_TYPE_DEFINITION,
|
'kind' => NodeKind::OBJECT_TYPE_DEFINITION,
|
||||||
'name' => $this->nameNode('Hello', $loc(5, 10)),
|
'name' => $this->nameNode('Hello', $loc(5, 10)),
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->typeNode('World', $loc(22, 27))
|
$this->typeNode('World', $loc(22, 27)),
|
||||||
],
|
],
|
||||||
'directives' => [],
|
'directives' => [],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
@ -349,13 +415,13 @@ type Hello {
|
|||||||
$this->nameNode('field', $loc(30, 35)),
|
$this->nameNode('field', $loc(30, 35)),
|
||||||
$this->typeNode('String', $loc(37, 43)),
|
$this->typeNode('String', $loc(37, 43)),
|
||||||
$loc(30, 43)
|
$loc(30, 43)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 45),
|
'loc' => $loc(0, 45),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 45)
|
],
|
||||||
|
'loc' => $loc(0, 45),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
@ -367,8 +433,10 @@ type Hello {
|
|||||||
public function testSimpleTypeInheritingMultipleInterfaces() : void
|
public function testSimpleTypeInheritingMultipleInterfaces() : void
|
||||||
{
|
{
|
||||||
$body = 'type Hello implements Wo & rld { field: String }';
|
$body = 'type Hello implements Wo & rld { field: String }';
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -378,7 +446,7 @@ type Hello {
|
|||||||
'name' => $this->nameNode('Hello', $loc(5, 10)),
|
'name' => $this->nameNode('Hello', $loc(5, 10)),
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->typeNode('Wo', $loc(22, 24)),
|
$this->typeNode('Wo', $loc(22, 24)),
|
||||||
$this->typeNode('rld', $loc(27, 30))
|
$this->typeNode('rld', $loc(27, 30)),
|
||||||
],
|
],
|
||||||
'directives' => [],
|
'directives' => [],
|
||||||
'fields' => [
|
'fields' => [
|
||||||
@ -386,13 +454,13 @@ type Hello {
|
|||||||
$this->nameNode('field', $loc(33, 38)),
|
$this->nameNode('field', $loc(33, 38)),
|
||||||
$this->typeNode('String', $loc(40, 46)),
|
$this->typeNode('String', $loc(40, 46)),
|
||||||
$loc(33, 46)
|
$loc(33, 46)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 48),
|
'loc' => $loc(0, 48),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 48)
|
],
|
||||||
|
'loc' => $loc(0, 48),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
@ -404,8 +472,11 @@ type Hello {
|
|||||||
public function testSimpleTypeInheritingMultipleInterfacesWithLeadingAmpersand() : void
|
public function testSimpleTypeInheritingMultipleInterfacesWithLeadingAmpersand() : void
|
||||||
{
|
{
|
||||||
$body = 'type Hello implements & Wo & rld { field: String }';
|
$body = 'type Hello implements & Wo & rld { field: String }';
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => 'Document',
|
'kind' => 'Document',
|
||||||
'definitions' => [
|
'definitions' => [
|
||||||
@ -439,8 +510,10 @@ type Hello {
|
|||||||
public function testSingleValueEnum() : void
|
public function testSingleValueEnum() : void
|
||||||
{
|
{
|
||||||
$body = 'enum Hello { WORLD }';
|
$body = 'enum Hello { WORLD }';
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -451,23 +524,36 @@ type Hello {
|
|||||||
'directives' => [],
|
'directives' => [],
|
||||||
'values' => [$this->enumValueNode('WORLD', $loc(13, 18))],
|
'values' => [$this->enumValueNode('WORLD', $loc(13, 18))],
|
||||||
'loc' => $loc(0, 20),
|
'loc' => $loc(0, 20),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 20)
|
],
|
||||||
|
'loc' => $loc(0, 20),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function enumValueNode($name, $loc)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'kind' => NodeKind::ENUM_VALUE_DEFINITION,
|
||||||
|
'name' => $this->nameNode($name, $loc),
|
||||||
|
'directives' => [],
|
||||||
|
'loc' => $loc,
|
||||||
|
'description' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Double value enum')
|
* @see it('Double value enum')
|
||||||
*/
|
*/
|
||||||
public function testDoubleValueEnum() : void
|
public function testDoubleValueEnum() : void
|
||||||
{
|
{
|
||||||
$body = 'enum Hello { WO, RLD }';
|
$body = 'enum Hello { WO, RLD }';
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -478,13 +564,13 @@ type Hello {
|
|||||||
'directives' => [],
|
'directives' => [],
|
||||||
'values' => [
|
'values' => [
|
||||||
$this->enumValueNode('WO', $loc(13, 15)),
|
$this->enumValueNode('WO', $loc(13, 15)),
|
||||||
$this->enumValueNode('RLD', $loc(17, 20))
|
$this->enumValueNode('RLD', $loc(17, 20)),
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 22),
|
'loc' => $loc(0, 22),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 22)
|
],
|
||||||
|
'loc' => $loc(0, 22),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
@ -500,7 +586,9 @@ interface Hello {
|
|||||||
world: String
|
world: String
|
||||||
}';
|
}';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -514,13 +602,13 @@ interface Hello {
|
|||||||
$this->nameNode('world', $loc(21, 26)),
|
$this->nameNode('world', $loc(21, 26)),
|
||||||
$this->typeNode('String', $loc(28, 34)),
|
$this->typeNode('String', $loc(28, 34)),
|
||||||
$loc(21, 34)
|
$loc(21, 34)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(1, 36),
|
'loc' => $loc(1, 36),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0,36)
|
],
|
||||||
|
'loc' => $loc(0, 36),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
@ -535,7 +623,9 @@ type Hello {
|
|||||||
world(flag: Boolean): String
|
world(flag: Boolean): String
|
||||||
}';
|
}';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -555,21 +645,34 @@ type Hello {
|
|||||||
$this->typeNode('Boolean', $loc(28, 35)),
|
$this->typeNode('Boolean', $loc(28, 35)),
|
||||||
null,
|
null,
|
||||||
$loc(22, 35)
|
$loc(22, 35)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
$loc(16, 44)
|
$loc(16, 44)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(1, 46),
|
'loc' => $loc(1, 46),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 46)
|
],
|
||||||
|
'loc' => $loc(0, 46),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function inputValueNode($name, $type, $defaultValue, $loc)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'kind' => NodeKind::INPUT_VALUE_DEFINITION,
|
||||||
|
'name' => $name,
|
||||||
|
'type' => $type,
|
||||||
|
'defaultValue' => $defaultValue,
|
||||||
|
'directives' => [],
|
||||||
|
'loc' => $loc,
|
||||||
|
'description' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Simple field with arg with default value')
|
* @see it('Simple field with arg with default value')
|
||||||
*/
|
*/
|
||||||
@ -580,7 +683,9 @@ type Hello {
|
|||||||
world(flag: Boolean = true): String
|
world(flag: Boolean = true): String
|
||||||
}';
|
}';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -600,16 +705,16 @@ type Hello {
|
|||||||
$this->typeNode('Boolean', $loc(28, 35)),
|
$this->typeNode('Boolean', $loc(28, 35)),
|
||||||
['kind' => NodeKind::BOOLEAN, 'value' => true, 'loc' => $loc(38, 42)],
|
['kind' => NodeKind::BOOLEAN, 'value' => true, 'loc' => $loc(38, 42)],
|
||||||
$loc(22, 42)
|
$loc(22, 42)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
$loc(16, 51)
|
$loc(16, 51)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(1, 53),
|
'loc' => $loc(1, 53),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 53)
|
],
|
||||||
|
'loc' => $loc(0, 53),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
@ -624,7 +729,9 @@ type Hello {
|
|||||||
world(things: [String]): String
|
world(things: [String]): String
|
||||||
}';
|
}';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -640,20 +747,26 @@ type Hello {
|
|||||||
$this->typeNode('String', $loc(41, 47)),
|
$this->typeNode('String', $loc(41, 47)),
|
||||||
[
|
[
|
||||||
$this->inputValueNode(
|
$this->inputValueNode(
|
||||||
$this->nameNode('things', $loc(22,28)),
|
$this->nameNode('things', $loc(22, 28)),
|
||||||
['kind' => NodeKind::LIST_TYPE, 'type' => $this->typeNode('String', $loc(31, 37)), 'loc' => $loc(30, 38)],
|
[
|
||||||
|
'kind' => NodeKind::LIST_TYPE,
|
||||||
|
'type' => $this->typeNode(
|
||||||
|
'String',
|
||||||
|
$loc(31, 37)
|
||||||
|
), 'loc' => $loc(30, 38),
|
||||||
|
],
|
||||||
null,
|
null,
|
||||||
$loc(22, 38)
|
$loc(22, 38)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
$loc(16, 47)
|
$loc(16, 47)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(1, 49),
|
'loc' => $loc(1, 49),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 49)
|
],
|
||||||
|
'loc' => $loc(0, 49),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
@ -669,7 +782,9 @@ type Hello {
|
|||||||
world(argOne: Boolean, argTwo: Int): String
|
world(argOne: Boolean, argTwo: Int): String
|
||||||
}';
|
}';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -695,16 +810,16 @@ type Hello {
|
|||||||
$this->typeNode('Int', $loc(47, 50)),
|
$this->typeNode('Int', $loc(47, 50)),
|
||||||
null,
|
null,
|
||||||
$loc(39, 50)
|
$loc(39, 50)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
$loc(16, 59)
|
$loc(16, 59)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(1, 61),
|
'loc' => $loc(1, 61),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 61)
|
],
|
||||||
|
'loc' => $loc(0, 61),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
@ -717,7 +832,10 @@ type Hello {
|
|||||||
{
|
{
|
||||||
$body = 'union Hello = World';
|
$body = 'union Hello = World';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
'definitions' => [
|
'definitions' => [
|
||||||
@ -727,10 +845,10 @@ type Hello {
|
|||||||
'directives' => [],
|
'directives' => [],
|
||||||
'types' => [$this->typeNode('World', $loc(14, 19))],
|
'types' => [$this->typeNode('World', $loc(14, 19))],
|
||||||
'loc' => $loc(0, 19),
|
'loc' => $loc(0, 19),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 19)
|
],
|
||||||
|
'loc' => $loc(0, 19),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
@ -743,7 +861,9 @@ type Hello {
|
|||||||
{
|
{
|
||||||
$body = 'union Hello = Wo | Rld';
|
$body = 'union Hello = Wo | Rld';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -754,18 +874,17 @@ type Hello {
|
|||||||
'directives' => [],
|
'directives' => [],
|
||||||
'types' => [
|
'types' => [
|
||||||
$this->typeNode('Wo', $loc(14, 16)),
|
$this->typeNode('Wo', $loc(14, 16)),
|
||||||
$this->typeNode('Rld', $loc(19, 22))
|
$this->typeNode('Rld', $loc(19, 22)),
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 22),
|
'loc' => $loc(0, 22),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 22)
|
],
|
||||||
|
'loc' => $loc(0, 22),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Union with two types and leading pipe')
|
* @see it('Union with two types and leading pipe')
|
||||||
*/
|
*/
|
||||||
@ -785,8 +904,8 @@ type Hello {
|
|||||||
$this->typeNode('Rld', ['start' => 21, 'end' => 24]),
|
$this->typeNode('Rld', ['start' => 21, 'end' => 24]),
|
||||||
],
|
],
|
||||||
'loc' => ['start' => 0, 'end' => 24],
|
'loc' => ['start' => 0, 'end' => 24],
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'loc' => ['start' => 0, 'end' => 24],
|
'loc' => ['start' => 0, 'end' => 24],
|
||||||
];
|
];
|
||||||
@ -848,7 +967,10 @@ type Hello {
|
|||||||
{
|
{
|
||||||
$body = 'scalar Hello';
|
$body = 'scalar Hello';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
'definitions' => [
|
'definitions' => [
|
||||||
@ -857,10 +979,10 @@ type Hello {
|
|||||||
'name' => $this->nameNode('Hello', $loc(7, 12)),
|
'name' => $this->nameNode('Hello', $loc(7, 12)),
|
||||||
'directives' => [],
|
'directives' => [],
|
||||||
'loc' => $loc(0, 12),
|
'loc' => $loc(0, 12),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 12)
|
],
|
||||||
|
'loc' => $loc(0, 12),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
@ -875,7 +997,9 @@ input Hello {
|
|||||||
world: String
|
world: String
|
||||||
}';
|
}';
|
||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
$loc = function ($start, $end) {
|
||||||
|
return TestUtils::locArray($start, $end);
|
||||||
|
};
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'kind' => NodeKind::DOCUMENT,
|
'kind' => NodeKind::DOCUMENT,
|
||||||
@ -890,13 +1014,13 @@ input Hello {
|
|||||||
$this->typeNode('String', $loc(24, 30)),
|
$this->typeNode('String', $loc(24, 30)),
|
||||||
null,
|
null,
|
||||||
$loc(17, 30)
|
$loc(17, 30)
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
'loc' => $loc(1, 32),
|
'loc' => $loc(1, 32),
|
||||||
'description' => null
|
'description' => null,
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'loc' => $loc(0, 32)
|
],
|
||||||
|
'loc' => $loc(0, 32),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||||
}
|
}
|
||||||
@ -980,81 +1104,4 @@ input Hello {
|
|||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, $doc->toArray(true));
|
$this->assertArraySubset($expected, $doc->toArray(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function typeNode($name, $loc)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'kind' => NodeKind::NAMED_TYPE,
|
|
||||||
'name' => ['kind' => NodeKind::NAME, 'value' => $name, 'loc' => $loc],
|
|
||||||
'loc' => $loc
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function nameNode($name, $loc)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'kind' => NodeKind::NAME,
|
|
||||||
'value' => $name,
|
|
||||||
'loc' => $loc
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function fieldNode($name, $type, $loc)
|
|
||||||
{
|
|
||||||
return $this->fieldNodeWithArgs($name, $type, [], $loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function fieldNodeWithArgs($name, $type, $args, $loc)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'kind' => NodeKind::FIELD_DEFINITION,
|
|
||||||
'name' => $name,
|
|
||||||
'arguments' => $args,
|
|
||||||
'type' => $type,
|
|
||||||
'directives' => [],
|
|
||||||
'loc' => $loc,
|
|
||||||
'description' => null
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function enumValueNode($name, $loc)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'kind' => NodeKind::ENUM_VALUE_DEFINITION,
|
|
||||||
'name' => $this->nameNode($name, $loc),
|
|
||||||
'directives' => [],
|
|
||||||
'loc' => $loc,
|
|
||||||
'description' => null
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function inputValueNode($name, $type, $defaultValue, $loc)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'kind' => NodeKind::INPUT_VALUE_DEFINITION,
|
|
||||||
'name' => $name,
|
|
||||||
'type' => $type,
|
|
||||||
'defaultValue' => $defaultValue,
|
|
||||||
'directives' => [],
|
|
||||||
'loc' => $loc,
|
|
||||||
'description' => null
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function loc($line, $column)
|
|
||||||
{
|
|
||||||
return new SourceLocation($line, $column);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function expectSyntaxError($text, $message, $location)
|
|
||||||
{
|
|
||||||
$this->expectException(SyntaxError::class);
|
|
||||||
$this->expectExceptionMessage($message);
|
|
||||||
try {
|
|
||||||
Parser::parse($text);
|
|
||||||
} catch (SyntaxError $error) {
|
|
||||||
$this->assertEquals([$location], $error->getLocations());
|
|
||||||
throw $error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests;
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Language;
|
||||||
|
|
||||||
use GraphQL\Language\AST\NameNode;
|
use GraphQL\Language\AST\NameNode;
|
||||||
use GraphQL\Language\AST\ScalarTypeDefinitionNode;
|
use GraphQL\Language\AST\ScalarTypeDefinitionNode;
|
||||||
@ -7,6 +10,7 @@ use GraphQL\Language\Parser;
|
|||||||
use GraphQL\Language\Printer;
|
use GraphQL\Language\Printer;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
use function file_get_contents;
|
||||||
|
|
||||||
class SchemaPrinterTest extends TestCase
|
class SchemaPrinterTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -16,7 +20,7 @@ class SchemaPrinterTest extends TestCase
|
|||||||
public function testPrintsMinimalAst() : void
|
public function testPrintsMinimalAst() : void
|
||||||
{
|
{
|
||||||
$ast = new ScalarTypeDefinitionNode([
|
$ast = new ScalarTypeDefinitionNode([
|
||||||
'name' => new NameNode(['value' => 'foo'])
|
'name' => new NameNode(['value' => 'foo']),
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('scalar foo', Printer::doPrint($ast));
|
$this->assertEquals('scalar foo', Printer::doPrint($ast));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests;
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Language;
|
||||||
|
|
||||||
use GraphQL\Language\AST\Location;
|
use GraphQL\Language\AST\Location;
|
||||||
use GraphQL\Language\AST\Node;
|
use GraphQL\Language\AST\Node;
|
||||||
@ -7,6 +10,13 @@ use GraphQL\Language\AST\NodeList;
|
|||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Utils\AST;
|
use GraphQL\Utils\AST;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function array_keys;
|
||||||
|
use function count;
|
||||||
|
use function file_get_contents;
|
||||||
|
use function get_class;
|
||||||
|
use function get_object_vars;
|
||||||
|
use function implode;
|
||||||
|
use function json_decode;
|
||||||
|
|
||||||
class SerializationTest extends TestCase
|
class SerializationTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -27,6 +37,50 @@ class SerializationTest extends TestCase
|
|||||||
$this->assertNodesAreEqual($parsedAst, $actualAst);
|
$this->assertNodesAreEqual($parsedAst, $actualAst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two nodes by actually iterating over all NodeLists, properly comparing locations (ignoring tokens), etc
|
||||||
|
*
|
||||||
|
* @param string[] $path
|
||||||
|
*/
|
||||||
|
private function assertNodesAreEqual(Node $expected, Node $actual, array $path = []) : void
|
||||||
|
{
|
||||||
|
$err = 'Mismatch at AST path: ' . implode(', ', $path);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(Node::class, $actual, $err);
|
||||||
|
$this->assertEquals(get_class($expected), get_class($actual), $err);
|
||||||
|
|
||||||
|
$expectedVars = get_object_vars($expected);
|
||||||
|
$actualVars = get_object_vars($actual);
|
||||||
|
$this->assertCount(count($expectedVars), $actualVars, $err);
|
||||||
|
$this->assertEquals(array_keys($expectedVars), array_keys($actualVars), $err);
|
||||||
|
|
||||||
|
foreach ($expectedVars as $name => $expectedValue) {
|
||||||
|
$actualValue = $actualVars[$name];
|
||||||
|
$tmpPath = $path;
|
||||||
|
$tmpPath[] = $name;
|
||||||
|
$err = 'Mismatch at AST path: ' . implode(', ', $tmpPath);
|
||||||
|
|
||||||
|
if ($expectedValue instanceof Node) {
|
||||||
|
$this->assertNodesAreEqual($expectedValue, $actualValue, $tmpPath);
|
||||||
|
} elseif ($expectedValue instanceof NodeList) {
|
||||||
|
$this->assertEquals(count($expectedValue), count($actualValue), $err);
|
||||||
|
$this->assertInstanceOf(NodeList::class, $actualValue, $err);
|
||||||
|
|
||||||
|
foreach ($expectedValue as $index => $listNode) {
|
||||||
|
$tmpPath2 = $tmpPath;
|
||||||
|
$tmpPath2[] = $index;
|
||||||
|
$this->assertNodesAreEqual($listNode, $actualValue[$index], $tmpPath2);
|
||||||
|
}
|
||||||
|
} elseif ($expectedValue instanceof Location) {
|
||||||
|
$this->assertInstanceOf(Location::class, $actualValue, $err);
|
||||||
|
$this->assertSame($expectedValue->start, $actualValue->start, $err);
|
||||||
|
$this->assertSame($expectedValue->end, $actualValue->end, $err);
|
||||||
|
} else {
|
||||||
|
$this->assertEquals($expectedValue, $actualValue, $err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function testSerializeSupportsNoLocationOption() : void
|
public function testSerializeSupportsNoLocationOption() : void
|
||||||
{
|
{
|
||||||
$kitchenSink = file_get_contents(__DIR__ . '/kitchen-sink.graphql');
|
$kitchenSink = file_get_contents(__DIR__ . '/kitchen-sink.graphql');
|
||||||
@ -43,50 +97,4 @@ class SerializationTest extends TestCase
|
|||||||
$parsedAst = Parser::parse($kitchenSink, ['noLocation' => true]);
|
$parsedAst = Parser::parse($kitchenSink, ['noLocation' => true]);
|
||||||
$this->assertNodesAreEqual($parsedAst, $actualAst);
|
$this->assertNodesAreEqual($parsedAst, $actualAst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares two nodes by actually iterating over all NodeLists, properly comparing locations (ignoring tokens), etc
|
|
||||||
*
|
|
||||||
* @param $expected
|
|
||||||
* @param $actual
|
|
||||||
* @param array $path
|
|
||||||
*/
|
|
||||||
private function assertNodesAreEqual($expected, $actual, $path = [])
|
|
||||||
{
|
|
||||||
$err = "Mismatch at AST path: " . implode(', ', $path);
|
|
||||||
|
|
||||||
$this->assertInstanceOf(Node::class, $actual, $err);
|
|
||||||
$this->assertEquals(get_class($expected), get_class($actual), $err);
|
|
||||||
|
|
||||||
$expectedVars = get_object_vars($expected);
|
|
||||||
$actualVars = get_object_vars($actual);
|
|
||||||
$this->assertSame(count($expectedVars), count($actualVars), $err);
|
|
||||||
$this->assertEquals(array_keys($expectedVars), array_keys($actualVars), $err);
|
|
||||||
|
|
||||||
foreach ($expectedVars as $name => $expectedValue) {
|
|
||||||
$actualValue = $actualVars[$name];
|
|
||||||
$tmpPath = $path;
|
|
||||||
$tmpPath[] = $name;
|
|
||||||
$err = "Mismatch at AST path: " . implode(', ', $tmpPath);
|
|
||||||
|
|
||||||
if ($expectedValue instanceof Node) {
|
|
||||||
$this->assertNodesAreEqual($expectedValue, $actualValue, $tmpPath);
|
|
||||||
} else if ($expectedValue instanceof NodeList) {
|
|
||||||
$this->assertEquals(count($expectedValue), count($actualValue), $err);
|
|
||||||
$this->assertInstanceOf(NodeList::class, $actualValue, $err);
|
|
||||||
|
|
||||||
foreach ($expectedValue as $index => $listNode) {
|
|
||||||
$tmpPath2 = $tmpPath;
|
|
||||||
$tmpPath2 [] = $index;
|
|
||||||
$this->assertNodesAreEqual($listNode, $actualValue[$index], $tmpPath2);
|
|
||||||
}
|
|
||||||
} else if ($expectedValue instanceof Location) {
|
|
||||||
$this->assertInstanceOf(Location::class, $actualValue, $err);
|
|
||||||
$this->assertSame($expectedValue->start, $actualValue->start, $err);
|
|
||||||
$this->assertSame($expectedValue->end, $actualValue->end, $err);
|
|
||||||
} else {
|
|
||||||
$this->assertEquals($expectedValue, $actualValue, $err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,41 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Language;
|
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Language;
|
||||||
|
|
||||||
use GraphQL\Language\AST\Location;
|
use GraphQL\Language\AST\Location;
|
||||||
use GraphQL\Language\AST\Node;
|
use GraphQL\Language\AST\Node;
|
||||||
use GraphQL\Language\AST\NodeList;
|
use GraphQL\Language\AST\NodeList;
|
||||||
|
use function get_object_vars;
|
||||||
|
use function is_array;
|
||||||
|
use function is_scalar;
|
||||||
|
|
||||||
class TestUtils
|
class TestUtils
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param Node $node
|
* @return mixed[]
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public static function nodeToArray(Node $node)
|
public static function nodeToArray(Node $node) : array
|
||||||
{
|
{
|
||||||
$result = [
|
$result = [
|
||||||
'kind' => $node->kind,
|
'kind' => $node->kind,
|
||||||
'loc' => self::locationToArray($node->loc)
|
'loc' => self::locationToArray($node->loc),
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach (get_object_vars($node) as $prop => $propValue) {
|
foreach (get_object_vars($node) as $prop => $propValue) {
|
||||||
if (isset($result[$prop]))
|
if (isset($result[$prop])) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_array($propValue) || $propValue instanceof NodeList) {
|
if (is_array($propValue) || $propValue instanceof NodeList) {
|
||||||
$tmp = [];
|
$tmp = [];
|
||||||
foreach ($propValue as $tmp1) {
|
foreach ($propValue as $tmp1) {
|
||||||
$tmp[] = $tmp1 instanceof Node ? self::nodeToArray($tmp1) : (array) $tmp1;
|
$tmp[] = $tmp1 instanceof Node ? self::nodeToArray($tmp1) : (array) $tmp1;
|
||||||
}
|
}
|
||||||
} else if ($propValue instanceof Node) {
|
} elseif ($propValue instanceof Node) {
|
||||||
$tmp = self::nodeToArray($propValue);
|
$tmp = self::nodeToArray($propValue);
|
||||||
} else if (is_scalar($propValue) || null === $propValue) {
|
} elseif (is_scalar($propValue) || $propValue === null) {
|
||||||
$tmp = $propValue;
|
$tmp = $propValue;
|
||||||
} else {
|
} else {
|
||||||
$tmp = null;
|
$tmp = null;
|
||||||
@ -38,27 +43,25 @@ class TestUtils
|
|||||||
|
|
||||||
$result[$prop] = $tmp;
|
$result[$prop] = $tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Location $loc
|
* @return int[]
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public static function locationToArray(Location $loc)
|
public static function locationToArray(Location $loc) : array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'start' => $loc->start,
|
'start' => $loc->start,
|
||||||
'end' => $loc->end
|
'end' => $loc->end,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $start
|
* @return int[]
|
||||||
* @param $end
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public static function locArray($start, $end)
|
public static function locArray(int $start, int $end) : array
|
||||||
{
|
{
|
||||||
return ['start' => $start, 'end' => $end];
|
return ['start' => $start, 'end' => $end];
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests;
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Language;
|
||||||
|
|
||||||
use GraphQL\Language\Token;
|
use GraphQL\Language\Token;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
@ -13,7 +16,7 @@ class TokenTest extends TestCase
|
|||||||
'kind' => 'Kind',
|
'kind' => 'Kind',
|
||||||
'value' => null,
|
'value' => null,
|
||||||
'line' => 3,
|
'line' => 3,
|
||||||
'column' => 5
|
'column' => 5,
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $token->toArray());
|
$this->assertEquals($expected, $token->toArray());
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Server\Psr7;
|
namespace GraphQL\Tests\Server\Psr7;
|
||||||
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Psr\Http\Message\StreamInterface;
|
use Psr\Http\Message\StreamInterface;
|
||||||
use Psr\Http\Message\UriInterface;
|
use Psr\Http\Message\UriInterface;
|
||||||
|
use function strtolower;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* phpcs:ignoreFile -- this is not a core file
|
||||||
|
*/
|
||||||
class PsrRequestStub implements ServerRequestInterface
|
class PsrRequestStub implements ServerRequestInterface
|
||||||
{
|
{
|
||||||
public $queryParams = [];
|
public $queryParams = [];
|
||||||
@ -13,14 +20,10 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
|
|
||||||
public $method;
|
public $method;
|
||||||
|
|
||||||
/**
|
/** @var PsrStreamStub */
|
||||||
* @var PsrStreamStub
|
|
||||||
*/
|
|
||||||
public $body;
|
public $body;
|
||||||
|
|
||||||
/**
|
/** @var mixed[] */
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public $parsedBody;
|
public $parsedBody;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,7 +35,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function getProtocolVersion()
|
public function getProtocolVersion()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,7 +53,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withProtocolVersion($version)
|
public function withProtocolVersion($version)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,7 +83,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function getHeaders()
|
public function getHeaders()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,7 +96,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function hasHeader($name)
|
public function hasHeader($name)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,7 +116,8 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
public function getHeader($name)
|
public function getHeader($name)
|
||||||
{
|
{
|
||||||
$name = strtolower($name);
|
$name = strtolower($name);
|
||||||
return isset($this->headers[$name]) ? $this->headers[$name] : [];
|
|
||||||
|
return $this->headers[$name] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,7 +141,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function getHeaderLine($name)
|
public function getHeaderLine($name)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,7 +161,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withHeader($name, $value)
|
public function withHeader($name, $value)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,7 +182,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withAddedHeader($name, $value)
|
public function withAddedHeader($name, $value)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -195,7 +199,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withoutHeader($name)
|
public function withoutHeader($name)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -223,7 +227,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withBody(StreamInterface $body)
|
public function withBody(StreamInterface $body)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -244,7 +248,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function getRequestTarget()
|
public function getRequestTarget()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -266,7 +270,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withRequestTarget($requestTarget)
|
public function withRequestTarget($requestTarget)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -296,7 +300,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withMethod($method)
|
public function withMethod($method)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -345,7 +349,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withUri(UriInterface $uri, $preserveHost = false)
|
public function withUri(UriInterface $uri, $preserveHost = false)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -359,7 +363,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function getServerParams()
|
public function getServerParams()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -374,7 +378,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function getCookieParams()
|
public function getCookieParams()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -396,7 +400,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withCookieParams(array $cookies)
|
public function withCookieParams(array $cookies)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -440,7 +444,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withQueryParams(array $query)
|
public function withQueryParams(array $query)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -457,7 +461,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function getUploadedFiles()
|
public function getUploadedFiles()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -473,7 +477,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withUploadedFiles(array $uploadedFiles)
|
public function withUploadedFiles(array $uploadedFiles)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -526,7 +530,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withParsedBody($data)
|
public function withParsedBody($data)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -542,7 +546,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function getAttributes()
|
public function getAttributes()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -562,7 +566,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function getAttribute($name, $default = null)
|
public function getAttribute($name, $default = null)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -582,7 +586,7 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withAttribute($name, $value)
|
public function withAttribute($name, $value)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -601,6 +605,6 @@ class PsrRequestStub implements ServerRequestInterface
|
|||||||
*/
|
*/
|
||||||
public function withoutAttribute($name)
|
public function withoutAttribute($name)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Server\Psr7;
|
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Server\Psr7;
|
||||||
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\StreamInterface;
|
use Psr\Http\Message\StreamInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* phpcs:ignoreFile -- this is not a core file
|
||||||
|
*/
|
||||||
class PsrResponseStub implements ResponseInterface
|
class PsrResponseStub implements ResponseInterface
|
||||||
{
|
{
|
||||||
public $headers = [];
|
public $headers = [];
|
||||||
@ -22,7 +27,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
*/
|
*/
|
||||||
public function getProtocolVersion()
|
public function getProtocolVersion()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,7 +45,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
*/
|
*/
|
||||||
public function withProtocolVersion($version)
|
public function withProtocolVersion($version)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,7 +75,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
*/
|
*/
|
||||||
public function getHeaders()
|
public function getHeaders()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,7 +88,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
*/
|
*/
|
||||||
public function hasHeader($name)
|
public function hasHeader($name)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,7 +107,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
*/
|
*/
|
||||||
public function getHeader($name)
|
public function getHeader($name)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,7 +131,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
*/
|
*/
|
||||||
public function getHeaderLine($name)
|
public function getHeaderLine($name)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,6 +153,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
{
|
{
|
||||||
$tmp = clone $this;
|
$tmp = clone $this;
|
||||||
$tmp->headers[$name][] = $value;
|
$tmp->headers[$name][] = $value;
|
||||||
|
|
||||||
return $tmp;
|
return $tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +175,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
*/
|
*/
|
||||||
public function withAddedHeader($name, $value)
|
public function withAddedHeader($name, $value)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,7 +192,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
*/
|
*/
|
||||||
public function withoutHeader($name)
|
public function withoutHeader($name)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,7 +202,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
*/
|
*/
|
||||||
public function getBody()
|
public function getBody()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -216,6 +222,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
{
|
{
|
||||||
$tmp = clone $this;
|
$tmp = clone $this;
|
||||||
$tmp->body = $body;
|
$tmp->body = $body;
|
||||||
|
|
||||||
return $tmp;
|
return $tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +236,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
*/
|
*/
|
||||||
public function getStatusCode()
|
public function getStatusCode()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,6 +263,7 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
{
|
{
|
||||||
$tmp = clone $this;
|
$tmp = clone $this;
|
||||||
$tmp->statusCode = $code;
|
$tmp->statusCode = $code;
|
||||||
|
|
||||||
return $tmp;
|
return $tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,6 +282,6 @@ class PsrResponseStub implements ResponseInterface
|
|||||||
*/
|
*/
|
||||||
public function getReasonPhrase()
|
public function getReasonPhrase()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Server\Psr7;
|
namespace GraphQL\Tests\Server\Psr7;
|
||||||
|
|
||||||
use Psr\Http\Message\StreamInterface;
|
use Psr\Http\Message\StreamInterface;
|
||||||
|
use function strlen;
|
||||||
|
use const SEEK_SET;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* phpcs:ignoreFile -- this is not a core file
|
||||||
|
*/
|
||||||
class PsrStreamStub implements StreamInterface
|
class PsrStreamStub implements StreamInterface
|
||||||
{
|
{
|
||||||
public $content;
|
public $content;
|
||||||
@ -33,7 +41,7 @@ class PsrStreamStub implements StreamInterface
|
|||||||
*/
|
*/
|
||||||
public function close()
|
public function close()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,7 +53,7 @@ class PsrStreamStub implements StreamInterface
|
|||||||
*/
|
*/
|
||||||
public function detach()
|
public function detach()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,7 +63,7 @@ class PsrStreamStub implements StreamInterface
|
|||||||
*/
|
*/
|
||||||
public function getSize()
|
public function getSize()
|
||||||
{
|
{
|
||||||
return strlen($this->content?:'');
|
return strlen($this->content ?: '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,7 +74,7 @@ class PsrStreamStub implements StreamInterface
|
|||||||
*/
|
*/
|
||||||
public function tell()
|
public function tell()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,7 +84,7 @@ class PsrStreamStub implements StreamInterface
|
|||||||
*/
|
*/
|
||||||
public function eof()
|
public function eof()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,7 +94,7 @@ class PsrStreamStub implements StreamInterface
|
|||||||
*/
|
*/
|
||||||
public function isSeekable()
|
public function isSeekable()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,7 +111,7 @@ class PsrStreamStub implements StreamInterface
|
|||||||
*/
|
*/
|
||||||
public function seek($offset, $whence = SEEK_SET)
|
public function seek($offset, $whence = SEEK_SET)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,7 +126,7 @@ class PsrStreamStub implements StreamInterface
|
|||||||
*/
|
*/
|
||||||
public function rewind()
|
public function rewind()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,6 +149,7 @@ class PsrStreamStub implements StreamInterface
|
|||||||
public function write($string)
|
public function write($string)
|
||||||
{
|
{
|
||||||
$this->content = $string;
|
$this->content = $string;
|
||||||
|
|
||||||
return strlen($string);
|
return strlen($string);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +160,7 @@ class PsrStreamStub implements StreamInterface
|
|||||||
*/
|
*/
|
||||||
public function isReadable()
|
public function isReadable()
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -166,7 +175,7 @@ class PsrStreamStub implements StreamInterface
|
|||||||
*/
|
*/
|
||||||
public function read($length)
|
public function read($length)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -195,6 +204,6 @@ class PsrStreamStub implements StreamInterface
|
|||||||
*/
|
*/
|
||||||
public function getMetadata($key = null)
|
public function getMetadata($key = null)
|
||||||
{
|
{
|
||||||
throw new \Exception("Not implemented");
|
throw new \Exception('Not implemented');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Server;
|
namespace GraphQL\Tests\Server;
|
||||||
|
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
use GraphQL\Server\Helper;
|
use GraphQL\Server\Helper;
|
||||||
use GraphQL\Tests\Server\Psr7\PsrStreamStub;
|
|
||||||
use GraphQL\Tests\Server\Psr7\PsrResponseStub;
|
use GraphQL\Tests\Server\Psr7\PsrResponseStub;
|
||||||
|
use GraphQL\Tests\Server\Psr7\PsrStreamStub;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function json_encode;
|
||||||
|
|
||||||
class PsrResponseTest extends TestCase
|
class PsrResponseTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Server;
|
namespace GraphQL\Tests\Server;
|
||||||
|
|
||||||
use GraphQL\Error\Debug;
|
use GraphQL\Error\Debug;
|
||||||
@ -14,12 +17,12 @@ use GraphQL\Server\ServerConfig;
|
|||||||
use GraphQL\Validator\DocumentValidator;
|
use GraphQL\Validator\DocumentValidator;
|
||||||
use GraphQL\Validator\Rules\CustomValidationRule;
|
use GraphQL\Validator\Rules\CustomValidationRule;
|
||||||
use GraphQL\Validator\ValidationContext;
|
use GraphQL\Validator\ValidationContext;
|
||||||
|
use function count;
|
||||||
|
use function sprintf;
|
||||||
|
|
||||||
class QueryExecutionTest extends ServerTestCase
|
class QueryExecutionTest extends ServerTestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var ServerConfig */
|
||||||
* @var ServerConfig
|
|
||||||
*/
|
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -34,20 +37,36 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$query = '{f1}';
|
$query = '{f1}';
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['f1' => 'f1'],
|
||||||
'f1' => 'f1'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertQueryResultEquals($expected, $query);
|
$this->assertQueryResultEquals($expected, $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function assertQueryResultEquals($expected, $query, $variables = null)
|
||||||
|
{
|
||||||
|
$result = $this->executeQuery($query, $variables);
|
||||||
|
$this->assertArraySubset($expected, $result->toArray(true));
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function executeQuery($query, $variables = null, $readonly = false)
|
||||||
|
{
|
||||||
|
$op = OperationParams::create(['query' => $query, 'variables' => $variables], $readonly);
|
||||||
|
$helper = new Helper();
|
||||||
|
$result = $helper->executeOperation($this->config, $op);
|
||||||
|
$this->assertInstanceOf(ExecutionResult::class, $result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
public function testReturnsSyntaxErrors() : void
|
public function testReturnsSyntaxErrors() : void
|
||||||
{
|
{
|
||||||
$query = '{f1';
|
$query = '{f1';
|
||||||
|
|
||||||
$result = $this->executeQuery($query);
|
$result = $this->executeQuery($query);
|
||||||
$this->assertSame(null, $result->data);
|
$this->assertNull($result->data);
|
||||||
$this->assertCount(1, $result->errors);
|
$this->assertCount(1, $result->errors);
|
||||||
$this->assertContains(
|
$this->assertContains(
|
||||||
'Syntax Error: Expected Name, found <EOF>',
|
'Syntax Error: Expected Name, found <EOF>',
|
||||||
@ -70,11 +89,12 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'fieldWithSafeException' => null,
|
'fieldWithSafeException' => null,
|
||||||
'f1' => 'f1'
|
'f1' => 'f1',
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' => 'This is the exception we want',
|
'message' => 'This is the exception we want',
|
||||||
|
|
||||||
'path' => ['fieldWithSafeException'],
|
'path' => ['fieldWithSafeException'],
|
||||||
'trace' => []
|
'trace' => []
|
||||||
]
|
]
|
||||||
@ -112,7 +132,7 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
}
|
}
|
||||||
';
|
';
|
||||||
|
|
||||||
$this->assertTrue(!isset($context->testedRootValue));
|
$this->assertTrue(! isset($context->testedRootValue));
|
||||||
$this->executeQuery($query);
|
$this->executeQuery($query);
|
||||||
$this->assertSame($rootValue, $context->testedRootValue);
|
$this->assertSame($rootValue, $context->testedRootValue);
|
||||||
}
|
}
|
||||||
@ -129,8 +149,8 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'a' => 'a',
|
'a' => 'a',
|
||||||
'b' => 'b'
|
'b' => 'b',
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertQueryResultEquals($expected, $query, $variables);
|
$this->assertQueryResultEquals($expected, $query, $variables);
|
||||||
}
|
}
|
||||||
@ -142,8 +162,8 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
';
|
';
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
['message' => 'Cannot query field "nonExistentField" on type "Query".']
|
['message' => 'Cannot query field "nonExistentField" on type "Query".'],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertQueryResultEquals($expected, $query);
|
$this->assertQueryResultEquals($expected, $query);
|
||||||
@ -151,15 +171,16 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$called = false;
|
$called = false;
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
new CustomValidationRule('SomeRule', function() use (&$called) {
|
new CustomValidationRule('SomeRule', function () use (&$called) {
|
||||||
$called = true;
|
$called = true;
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
})
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->config->setValidationRules($rules);
|
$this->config->setValidationRules($rules);
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => []
|
'data' => [],
|
||||||
];
|
];
|
||||||
$this->assertQueryResultEquals($expected, $query);
|
$this->assertQueryResultEquals($expected, $query);
|
||||||
$this->assertTrue($called);
|
$this->assertTrue($called);
|
||||||
@ -170,11 +191,12 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$called = false;
|
$called = false;
|
||||||
$params = $doc = $operationType = null;
|
$params = $doc = $operationType = null;
|
||||||
|
|
||||||
$this->config->setValidationRules(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
|
$this->config->setValidationRules(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
|
||||||
$called = true;
|
$called = true;
|
||||||
$params = $p;
|
$params = $p;
|
||||||
$doc = $d;
|
$doc = $d;
|
||||||
$operationType = $o;
|
$operationType = $o;
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -193,18 +215,20 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$called1 = false;
|
$called1 = false;
|
||||||
$called2 = false;
|
$called2 = false;
|
||||||
|
|
||||||
$this->config->setValidationRules(function(OperationParams $params) use ($q1, $q2, &$called1, &$called2) {
|
$this->config->setValidationRules(function (OperationParams $params) use ($q1, &$called1, &$called2) {
|
||||||
if ($params->query === $q1) {
|
if ($params->query === $q1) {
|
||||||
$called1 = true;
|
$called1 = true;
|
||||||
|
|
||||||
return DocumentValidator::allRules();
|
return DocumentValidator::allRules();
|
||||||
} else {
|
|
||||||
$called2 = true;
|
|
||||||
return [
|
|
||||||
new CustomValidationRule('MyRule', function(ValidationContext $context) {
|
|
||||||
$context->reportError(new Error("This is the error we are looking for!"));
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$called2 = true;
|
||||||
|
|
||||||
|
return [
|
||||||
|
new CustomValidationRule('MyRule', function (ValidationContext $context) {
|
||||||
|
$context->reportError(new Error('This is the error we are looking for!'));
|
||||||
|
}),
|
||||||
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
$expected = ['data' => ['f1' => 'f1']];
|
$expected = ['data' => ['f1' => 'f1']];
|
||||||
@ -236,22 +260,28 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' => 'Persisted queries are not supported by this server',
|
'message' => 'Persisted queries are not supported by this server',
|
||||||
'category' => 'request'
|
'category' => 'request',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function executePersistedQuery($queryId, $variables = null)
|
||||||
|
{
|
||||||
|
$op = OperationParams::create(['queryId' => $queryId, 'variables' => $variables]);
|
||||||
|
$helper = new Helper();
|
||||||
|
$result = $helper->executeOperation($this->config, $op);
|
||||||
|
$this->assertInstanceOf(ExecutionResult::class, $result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
public function testBatchedQueriesAreDisabledByDefault() : void
|
public function testBatchedQueriesAreDisabledByDefault() : void
|
||||||
{
|
{
|
||||||
$batch = [
|
$batch = [
|
||||||
[
|
['query' => '{invalid}'],
|
||||||
'query' => '{invalid}'
|
['query' => '{f1,fieldWithSafeException}'],
|
||||||
],
|
|
||||||
[
|
|
||||||
'query' => '{f1,fieldWithSafeException}'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = $this->executeBatchedQuery($batch);
|
$result = $this->executeBatchedQuery($batch);
|
||||||
@ -261,17 +291,17 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' => 'Batched queries are not supported by this server',
|
'message' => 'Batched queries are not supported by this server',
|
||||||
'category' => 'request'
|
'category' => 'request',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' => 'Batched queries are not supported by this server',
|
'message' => 'Batched queries are not supported by this server',
|
||||||
'category' => 'request'
|
'category' => 'request',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -279,6 +309,31 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$this->assertEquals($expected[1], $result[1]->toArray());
|
$this->assertEquals($expected[1], $result[1]->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[][] $qs
|
||||||
|
*/
|
||||||
|
private function executeBatchedQuery(array $qs)
|
||||||
|
{
|
||||||
|
$batch = [];
|
||||||
|
foreach ($qs as $params) {
|
||||||
|
$batch[] = OperationParams::create($params);
|
||||||
|
}
|
||||||
|
$helper = new Helper();
|
||||||
|
$result = $helper->executeBatch($this->config, $batch);
|
||||||
|
$this->assertInternalType('array', $result);
|
||||||
|
$this->assertCount(count($qs), $result);
|
||||||
|
|
||||||
|
foreach ($result as $index => $entry) {
|
||||||
|
$this->assertInstanceOf(
|
||||||
|
ExecutionResult::class,
|
||||||
|
$entry,
|
||||||
|
sprintf('Result at %s is not an instance of %s', $index, ExecutionResult::class)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
public function testMutationsAreNotAllowedInReadonlyMode() : void
|
public function testMutationsAreNotAllowedInReadonlyMode() : void
|
||||||
{
|
{
|
||||||
$mutation = 'mutation { a }';
|
$mutation = 'mutation { a }';
|
||||||
@ -287,9 +342,9 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' => 'GET supports only query operation',
|
'message' => 'GET supports only query operation',
|
||||||
'category' => 'request'
|
'category' => 'request',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = $this->executeQuery($mutation, null, true);
|
$result = $this->executeQuery($mutation, null, true);
|
||||||
@ -299,9 +354,10 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
public function testAllowsPersistentQueries() : void
|
public function testAllowsPersistentQueries() : void
|
||||||
{
|
{
|
||||||
$called = false;
|
$called = false;
|
||||||
$this->config->setPersistentQueryLoader(function($queryId, OperationParams $params) use (&$called) {
|
$this->config->setPersistentQueryLoader(function ($queryId, OperationParams $params) use (&$called) {
|
||||||
$called = true;
|
$called = true;
|
||||||
$this->assertEquals('some-id', $queryId);
|
$this->assertEquals('some-id', $queryId);
|
||||||
|
|
||||||
return '{f1}';
|
return '{f1}';
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -309,17 +365,16 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$this->assertTrue($called);
|
$this->assertTrue($called);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['f1' => 'f1'],
|
||||||
'f1' => 'f1'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
// Make sure it allows returning document node:
|
// Make sure it allows returning document node:
|
||||||
$called = false;
|
$called = false;
|
||||||
$this->config->setPersistentQueryLoader(function($queryId, OperationParams $params) use (&$called) {
|
$this->config->setPersistentQueryLoader(function ($queryId, OperationParams $params) use (&$called) {
|
||||||
$called = true;
|
$called = true;
|
||||||
$this->assertEquals('some-id', $queryId);
|
$this->assertEquals('some-id', $queryId);
|
||||||
|
|
||||||
return Parser::parse('{f1}');
|
return Parser::parse('{f1}');
|
||||||
});
|
});
|
||||||
$result = $this->executePersistedQuery('some-id');
|
$result = $this->executePersistedQuery('some-id');
|
||||||
@ -334,7 +389,7 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
'Persistent query loader must return query string or instance of GraphQL\Language\AST\DocumentNode ' .
|
'Persistent query loader must return query string or instance of GraphQL\Language\AST\DocumentNode ' .
|
||||||
'but got: {"err":"err"}'
|
'but got: {"err":"err"}'
|
||||||
);
|
);
|
||||||
$this->config->setPersistentQueryLoader(function($queryId, OperationParams $params) use (&$called) {
|
$this->config->setPersistentQueryLoader(function () {
|
||||||
return ['err' => 'err'];
|
return ['err' => 'err'];
|
||||||
});
|
});
|
||||||
$this->executePersistedQuery('some-id');
|
$this->executePersistedQuery('some-id');
|
||||||
@ -342,7 +397,7 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
|
|
||||||
public function testPersistedQueriesAreStillValidatedByDefault() : void
|
public function testPersistedQueriesAreStillValidatedByDefault() : void
|
||||||
{
|
{
|
||||||
$this->config->setPersistentQueryLoader(function() {
|
$this->config->setPersistentQueryLoader(function () {
|
||||||
return '{invalid}';
|
return '{invalid}';
|
||||||
});
|
});
|
||||||
$result = $this->executePersistedQuery('some-id');
|
$result = $this->executePersistedQuery('some-id');
|
||||||
@ -350,36 +405,35 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' => 'Cannot query field "invalid" on type "Query".',
|
'message' => 'Cannot query field "invalid" on type "Query".',
|
||||||
'locations' => [ ['line' => 1, 'column' => 2] ],
|
'locations' => [['line' => 1, 'column' => 2]],
|
||||||
'category' => 'graphql'
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAllowSkippingValidationForPersistedQueries() : void
|
public function testAllowSkippingValidationForPersistedQueries() : void
|
||||||
{
|
{
|
||||||
$this->config
|
$this->config
|
||||||
->setPersistentQueryLoader(function($queryId) {
|
->setPersistentQueryLoader(function ($queryId) {
|
||||||
if ($queryId === 'some-id') {
|
if ($queryId === 'some-id') {
|
||||||
return '{invalid}';
|
return '{invalid}';
|
||||||
} else {
|
|
||||||
return '{invalid2}';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return '{invalid2}';
|
||||||
})
|
})
|
||||||
->setValidationRules(function(OperationParams $params) {
|
->setValidationRules(function (OperationParams $params) {
|
||||||
if ($params->queryId === 'some-id') {
|
if ($params->queryId === 'some-id') {
|
||||||
return [];
|
return [];
|
||||||
} else {
|
|
||||||
return DocumentValidator::allRules();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return DocumentValidator::allRules();
|
||||||
});
|
});
|
||||||
|
|
||||||
$result = $this->executePersistedQuery('some-id');
|
$result = $this->executePersistedQuery('some-id');
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => []
|
'data' => [],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
@ -388,10 +442,10 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'message' => 'Cannot query field "invalid2" on type "Query".',
|
'message' => 'Cannot query field "invalid2" on type "Query".',
|
||||||
'locations' => [ ['line' => 1, 'column' => 2] ],
|
'locations' => [['line' => 1, 'column' => 2]],
|
||||||
'category' => 'graphql'
|
'category' => 'graphql',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expected, $result->toArray());
|
$this->assertEquals($expected, $result->toArray());
|
||||||
}
|
}
|
||||||
@ -400,7 +454,7 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
{
|
{
|
||||||
$this->expectException(InvariantViolation::class);
|
$this->expectException(InvariantViolation::class);
|
||||||
$this->expectExceptionMessage('Expecting validation rules to be array or callable returning array, but got: instance of stdClass');
|
$this->expectExceptionMessage('Expecting validation rules to be array or callable returning array, but got: instance of stdClass');
|
||||||
$this->config->setValidationRules(function(OperationParams $params) {
|
$this->config->setValidationRules(function (OperationParams $params) {
|
||||||
return new \stdClass();
|
return new \stdClass();
|
||||||
});
|
});
|
||||||
$this->executeQuery('{f1}');
|
$this->executeQuery('{f1}');
|
||||||
@ -411,12 +465,8 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$this->config->setQueryBatching(true);
|
$this->config->setQueryBatching(true);
|
||||||
|
|
||||||
$batch = [
|
$batch = [
|
||||||
[
|
['query' => '{invalid}'],
|
||||||
'query' => '{invalid}'
|
['query' => '{f1,fieldWithSafeException}'],
|
||||||
],
|
|
||||||
[
|
|
||||||
'query' => '{f1,fieldWithSafeException}'
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'query' => '
|
'query' => '
|
||||||
query ($a: String!, $b: String!) {
|
query ($a: String!, $b: String!) {
|
||||||
@ -425,14 +475,14 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
}
|
}
|
||||||
',
|
',
|
||||||
'variables' => ['a' => 'a', 'b' => 'b'],
|
'variables' => ['a' => 'a', 'b' => 'b'],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = $this->executeBatchedQuery($batch);
|
$result = $this->executeBatchedQuery($batch);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
[
|
[
|
||||||
'errors' => [['message' => 'Cannot query field "invalid" on type "Query".']]
|
'errors' => [['message' => 'Cannot query field "invalid" on type "Query".']],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'data' => [
|
'data' => [
|
||||||
@ -440,15 +490,15 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
'fieldWithSafeException' => null
|
'fieldWithSafeException' => null
|
||||||
],
|
],
|
||||||
'errors' => [
|
'errors' => [
|
||||||
['message' => 'This is the exception we want']
|
['message' => 'This is the exception we want'],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'data' => [
|
'data' => [
|
||||||
'a' => 'a',
|
'a' => 'a',
|
||||||
'b' => 'b'
|
'b' => 'b',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected[0], $result[0]->toArray());
|
$this->assertArraySubset($expected[0], $result[0]->toArray());
|
||||||
@ -459,15 +509,9 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
public function testDeferredsAreSharedAmongAllBatchedQueries() : void
|
public function testDeferredsAreSharedAmongAllBatchedQueries() : void
|
||||||
{
|
{
|
||||||
$batch = [
|
$batch = [
|
||||||
[
|
['query' => '{dfd(num: 1)}'],
|
||||||
'query' => '{dfd(num: 1)}'
|
['query' => '{dfd(num: 2)}'],
|
||||||
],
|
['query' => '{dfd(num: 3)}'],
|
||||||
[
|
|
||||||
'query' => '{dfd(num: 2)}'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'query' => '{dfd(num: 3)}',
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$calls = [];
|
$calls = [];
|
||||||
@ -476,13 +520,14 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
->setQueryBatching(true)
|
->setQueryBatching(true)
|
||||||
->setRootValue('1')
|
->setRootValue('1')
|
||||||
->setContext([
|
->setContext([
|
||||||
'buffer' => function($num) use (&$calls) {
|
'buffer' => function ($num) use (&$calls) {
|
||||||
$calls[] = "buffer: $num";
|
$calls[] = sprintf('buffer: %d', $num);
|
||||||
|
},
|
||||||
|
'load' => function ($num) use (&$calls) {
|
||||||
|
$calls[] = sprintf('load: %d', $num);
|
||||||
|
|
||||||
|
return sprintf('loaded: %d', $num);
|
||||||
},
|
},
|
||||||
'load' => function($num) use (&$calls) {
|
|
||||||
$calls[] = "load: $num";
|
|
||||||
return "loaded: $num";
|
|
||||||
}
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$result = $this->executeBatchedQuery($batch);
|
$result = $this->executeBatchedQuery($batch);
|
||||||
@ -499,19 +544,13 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
[
|
[
|
||||||
'data' => [
|
'data' => ['dfd' => 'loaded: 1'],
|
||||||
'dfd' => 'loaded: 1'
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'data' => [
|
'data' => ['dfd' => 'loaded: 2'],
|
||||||
'dfd' => 'loaded: 2'
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'data' => [
|
'data' => ['dfd' => 'loaded: 3'],
|
||||||
'dfd' => 'loaded: 3'
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -546,7 +585,7 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$called = false;
|
$called = false;
|
||||||
$params = $doc = $operationType = null;
|
$params = $doc = $operationType = null;
|
||||||
|
|
||||||
$this->config->setContext(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
|
$this->config->setContext(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
|
||||||
$called = true;
|
$called = true;
|
||||||
$params = $p;
|
$params = $p;
|
||||||
$doc = $d;
|
$doc = $d;
|
||||||
@ -566,7 +605,7 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$called = false;
|
$called = false;
|
||||||
$params = $doc = $operationType = null;
|
$params = $doc = $operationType = null;
|
||||||
|
|
||||||
$this->config->setRootValue(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
|
$this->config->setRootValue(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
|
||||||
$called = true;
|
$called = true;
|
||||||
$params = $p;
|
$params = $p;
|
||||||
$doc = $d;
|
$doc = $d;
|
||||||
@ -585,9 +624,10 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
{
|
{
|
||||||
$called = false;
|
$called = false;
|
||||||
$error = null;
|
$error = null;
|
||||||
$this->config->setErrorFormatter(function($e) use (&$called, &$error) {
|
$this->config->setErrorFormatter(function ($e) use (&$called, &$error) {
|
||||||
$called = true;
|
$called = true;
|
||||||
$error = $e;
|
$error = $e;
|
||||||
|
|
||||||
return ['test' => 'formatted'];
|
return ['test' => 'formatted'];
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -596,8 +636,8 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$formatted = $result->toArray();
|
$formatted = $result->toArray();
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
['test' => 'formatted']
|
['test' => 'formatted'],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertTrue($called);
|
$this->assertTrue($called);
|
||||||
$this->assertArraySubset($expected, $formatted);
|
$this->assertArraySubset($expected, $formatted);
|
||||||
@ -609,9 +649,9 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
'errors' => [
|
'errors' => [
|
||||||
[
|
[
|
||||||
'test' => 'formatted',
|
'test' => 'formatted',
|
||||||
'trace' => []
|
'trace' => [],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($expected, $formatted);
|
$this->assertArraySubset($expected, $formatted);
|
||||||
}
|
}
|
||||||
@ -621,12 +661,13 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$called = false;
|
$called = false;
|
||||||
$errors = null;
|
$errors = null;
|
||||||
$formatter = null;
|
$formatter = null;
|
||||||
$this->config->setErrorsHandler(function($e, $f) use (&$called, &$errors, &$formatter) {
|
$this->config->setErrorsHandler(function ($e, $f) use (&$called, &$errors, &$formatter) {
|
||||||
$called = true;
|
$called = true;
|
||||||
$errors = $e;
|
$errors = $e;
|
||||||
$formatter = $f;
|
$formatter = $f;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
['test' => 'handled']
|
['test' => 'handled'],
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -636,8 +677,8 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$formatted = $result->toArray();
|
$formatted = $result->toArray();
|
||||||
$expected = [
|
$expected = [
|
||||||
'errors' => [
|
'errors' => [
|
||||||
['test' => 'handled']
|
['test' => 'handled'],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertTrue($called);
|
$this->assertTrue($called);
|
||||||
$this->assertArraySubset($expected, $formatted);
|
$this->assertArraySubset($expected, $formatted);
|
||||||
@ -646,46 +687,4 @@ class QueryExecutionTest extends ServerTestCase
|
|||||||
$this->assertInternalType('callable', $formatter);
|
$this->assertInternalType('callable', $formatter);
|
||||||
$this->assertArraySubset($expected, $formatted);
|
$this->assertArraySubset($expected, $formatted);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function executePersistedQuery($queryId, $variables = null)
|
|
||||||
{
|
|
||||||
$op = OperationParams::create(['queryId' => $queryId, 'variables' => $variables]);
|
|
||||||
$helper = new Helper();
|
|
||||||
$result = $helper->executeOperation($this->config, $op);
|
|
||||||
$this->assertInstanceOf(ExecutionResult::class, $result);
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function executeQuery($query, $variables = null, $readonly = false)
|
|
||||||
{
|
|
||||||
$op = OperationParams::create(['query' => $query, 'variables' => $variables], $readonly);
|
|
||||||
$helper = new Helper();
|
|
||||||
$result = $helper->executeOperation($this->config, $op);
|
|
||||||
$this->assertInstanceOf(ExecutionResult::class, $result);
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function executeBatchedQuery(array $qs)
|
|
||||||
{
|
|
||||||
$batch = [];
|
|
||||||
foreach ($qs as $params) {
|
|
||||||
$batch[] = OperationParams::create($params);
|
|
||||||
}
|
|
||||||
$helper = new Helper();
|
|
||||||
$result = $helper->executeBatch($this->config, $batch);
|
|
||||||
$this->assertInternalType('array', $result);
|
|
||||||
$this->assertCount(count($qs), $result);
|
|
||||||
|
|
||||||
foreach ($result as $index => $entry) {
|
|
||||||
$this->assertInstanceOf(ExecutionResult::class, $entry, "Result at $index is not an instance of " . ExecutionResult::class);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function assertQueryResultEquals($expected, $query, $variables = null)
|
|
||||||
{
|
|
||||||
$result = $this->executeQuery($query, $variables);
|
|
||||||
$this->assertArraySubset($expected, $result->toArray(true));
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Server;
|
namespace GraphQL\Tests\Server;
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Server\Helper;
|
use GraphQL\Server\Helper;
|
||||||
use GraphQL\Server\OperationParams;
|
use GraphQL\Server\OperationParams;
|
||||||
@ -9,6 +11,8 @@ use GraphQL\Server\RequestError;
|
|||||||
use GraphQL\Tests\Server\Psr7\PsrRequestStub;
|
use GraphQL\Tests\Server\Psr7\PsrRequestStub;
|
||||||
use GraphQL\Tests\Server\Psr7\PsrStreamStub;
|
use GraphQL\Tests\Server\Psr7\PsrStreamStub;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function json_decode;
|
||||||
|
use function json_encode;
|
||||||
|
|
||||||
class RequestParsingTest extends TestCase
|
class RequestParsingTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -17,7 +21,7 @@ class RequestParsingTest extends TestCase
|
|||||||
$query = '{my query}';
|
$query = '{my query}';
|
||||||
$parsed = [
|
$parsed = [
|
||||||
'raw' => $this->parseRawRequest('application/graphql', $query),
|
'raw' => $this->parseRawRequest('application/graphql', $query),
|
||||||
'psr' => $this->parsePsrRequest('application/graphql', $query)
|
'psr' => $this->parsePsrRequest('application/graphql', $query),
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($parsed as $source => $parsedBody) {
|
foreach ($parsed as $source => $parsedBody) {
|
||||||
@ -26,6 +30,77 @@ class RequestParsingTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $contentType
|
||||||
|
* @param string $content
|
||||||
|
*
|
||||||
|
* @return OperationParams|OperationParams[]
|
||||||
|
*/
|
||||||
|
private function parseRawRequest($contentType, $content, string $method = 'POST')
|
||||||
|
{
|
||||||
|
$_SERVER['CONTENT_TYPE'] = $contentType;
|
||||||
|
$_SERVER['REQUEST_METHOD'] = $method;
|
||||||
|
|
||||||
|
$helper = new Helper();
|
||||||
|
|
||||||
|
return $helper->parseHttpRequest(function () use ($content) {
|
||||||
|
return $content;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $contentType
|
||||||
|
* @param string $content
|
||||||
|
*
|
||||||
|
* @return OperationParams|OperationParams[]
|
||||||
|
*/
|
||||||
|
private function parsePsrRequest($contentType, $content, string $method = 'POST')
|
||||||
|
{
|
||||||
|
$psrRequestBody = new PsrStreamStub();
|
||||||
|
$psrRequestBody->content = $content;
|
||||||
|
|
||||||
|
$psrRequest = new PsrRequestStub();
|
||||||
|
$psrRequest->headers['content-type'] = [$contentType];
|
||||||
|
$psrRequest->method = $method;
|
||||||
|
$psrRequest->body = $psrRequestBody;
|
||||||
|
|
||||||
|
if ($contentType === 'application/json') {
|
||||||
|
$parsedBody = json_decode($content, true);
|
||||||
|
$parsedBody = $parsedBody === false ? null : $parsedBody;
|
||||||
|
} else {
|
||||||
|
$parsedBody = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$psrRequest->parsedBody = $parsedBody;
|
||||||
|
|
||||||
|
$helper = new Helper();
|
||||||
|
|
||||||
|
return $helper->parsePsrRequest($psrRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OperationParams $params
|
||||||
|
* @param string $query
|
||||||
|
* @param string $queryId
|
||||||
|
* @param mixed|null $variables
|
||||||
|
* @param string $operation
|
||||||
|
*/
|
||||||
|
private function assertValidOperationParams(
|
||||||
|
$params,
|
||||||
|
$query,
|
||||||
|
$queryId = null,
|
||||||
|
$variables = null,
|
||||||
|
$operation = null,
|
||||||
|
$message = ''
|
||||||
|
) {
|
||||||
|
$this->assertInstanceOf(OperationParams::class, $params, $message);
|
||||||
|
|
||||||
|
$this->assertSame($query, $params->query, $message);
|
||||||
|
$this->assertSame($queryId, $params->queryId, $message);
|
||||||
|
$this->assertSame($variables, $params->variables, $message);
|
||||||
|
$this->assertSame($operation, $params->operation, $message);
|
||||||
|
}
|
||||||
|
|
||||||
public function testParsesUrlencodedRequest() : void
|
public function testParsesUrlencodedRequest() : void
|
||||||
{
|
{
|
||||||
$query = '{my query}';
|
$query = '{my query}';
|
||||||
@ -35,11 +110,11 @@ class RequestParsingTest extends TestCase
|
|||||||
$post = [
|
$post = [
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'variables' => $variables,
|
'variables' => $variables,
|
||||||
'operationName' => $operation
|
'operationName' => $operation,
|
||||||
];
|
];
|
||||||
$parsed = [
|
$parsed = [
|
||||||
'raw' => $this->parseRawFormUrlencodedRequest($post),
|
'raw' => $this->parseRawFormUrlencodedRequest($post),
|
||||||
'psr' => $this->parsePsrFormUrlEncodedRequest($post)
|
'psr' => $this->parsePsrFormUrlEncodedRequest($post),
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($parsed as $method => $parsedBody) {
|
foreach ($parsed as $method => $parsedBody) {
|
||||||
@ -48,6 +123,39 @@ class RequestParsingTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[] $postValue
|
||||||
|
* @return OperationParams|OperationParams[]
|
||||||
|
*/
|
||||||
|
private function parseRawFormUrlencodedRequest($postValue)
|
||||||
|
{
|
||||||
|
$_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
|
||||||
|
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||||
|
$_POST = $postValue;
|
||||||
|
|
||||||
|
$helper = new Helper();
|
||||||
|
|
||||||
|
return $helper->parseHttpRequest(function () {
|
||||||
|
throw new InvariantViolation("Shouldn't read from php://input for urlencoded request");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[] $postValue
|
||||||
|
* @return OperationParams[]|OperationParams
|
||||||
|
*/
|
||||||
|
private function parsePsrFormUrlEncodedRequest($postValue)
|
||||||
|
{
|
||||||
|
$psrRequest = new PsrRequestStub();
|
||||||
|
$psrRequest->headers['content-type'] = ['application/x-www-form-urlencoded'];
|
||||||
|
$psrRequest->method = 'POST';
|
||||||
|
$psrRequest->parsedBody = $postValue;
|
||||||
|
|
||||||
|
$helper = new Helper();
|
||||||
|
|
||||||
|
return $helper->parsePsrRequest($psrRequest);
|
||||||
|
}
|
||||||
|
|
||||||
public function testParsesGetRequest() : void
|
public function testParsesGetRequest() : void
|
||||||
{
|
{
|
||||||
$query = '{my query}';
|
$query = '{my query}';
|
||||||
@ -57,11 +165,11 @@ class RequestParsingTest extends TestCase
|
|||||||
$get = [
|
$get = [
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'variables' => $variables,
|
'variables' => $variables,
|
||||||
'operationName' => $operation
|
'operationName' => $operation,
|
||||||
];
|
];
|
||||||
$parsed = [
|
$parsed = [
|
||||||
'raw' => $this->parseRawGetRequest($get),
|
'raw' => $this->parseRawGetRequest($get),
|
||||||
'psr' => $this->parsePsrGetRequest($get)
|
'psr' => $this->parsePsrGetRequest($get),
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($parsed as $method => $parsedBody) {
|
foreach ($parsed as $method => $parsedBody) {
|
||||||
@ -70,6 +178,37 @@ class RequestParsingTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[] $getValue
|
||||||
|
* @return OperationParams
|
||||||
|
*/
|
||||||
|
private function parseRawGetRequest($getValue)
|
||||||
|
{
|
||||||
|
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||||
|
$_GET = $getValue;
|
||||||
|
|
||||||
|
$helper = new Helper();
|
||||||
|
|
||||||
|
return $helper->parseHttpRequest(function () {
|
||||||
|
throw new InvariantViolation("Shouldn't read from php://input for urlencoded request");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[] $getValue
|
||||||
|
* @return OperationParams[]|OperationParams
|
||||||
|
*/
|
||||||
|
private function parsePsrGetRequest($getValue)
|
||||||
|
{
|
||||||
|
$psrRequest = new PsrRequestStub();
|
||||||
|
$psrRequest->method = 'GET';
|
||||||
|
$psrRequest->queryParams = $getValue;
|
||||||
|
|
||||||
|
$helper = new Helper();
|
||||||
|
|
||||||
|
return $helper->parsePsrRequest($psrRequest);
|
||||||
|
}
|
||||||
|
|
||||||
public function testParsesMultipartFormdataRequest() : void
|
public function testParsesMultipartFormdataRequest() : void
|
||||||
{
|
{
|
||||||
$query = '{my query}';
|
$query = '{my query}';
|
||||||
@ -79,11 +218,11 @@ class RequestParsingTest extends TestCase
|
|||||||
$post = [
|
$post = [
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'variables' => $variables,
|
'variables' => $variables,
|
||||||
'operationName' => $operation
|
'operationName' => $operation,
|
||||||
];
|
];
|
||||||
$parsed = [
|
$parsed = [
|
||||||
'raw' => $this->parseRawMultipartFormdataRequest($post),
|
'raw' => $this->parseRawMultipartFormdataRequest($post),
|
||||||
'psr' => $this->parsePsrMultipartFormdataRequest($post)
|
'psr' => $this->parsePsrMultipartFormdataRequest($post),
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($parsed as $method => $parsedBody) {
|
foreach ($parsed as $method => $parsedBody) {
|
||||||
@ -92,6 +231,39 @@ class RequestParsingTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[] $postValue
|
||||||
|
* @return OperationParams|OperationParams[]
|
||||||
|
*/
|
||||||
|
private function parseRawMultipartFormDataRequest($postValue)
|
||||||
|
{
|
||||||
|
$_SERVER['CONTENT_TYPE'] = 'multipart/form-data; boundary=----FormBoundary';
|
||||||
|
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||||
|
$_POST = $postValue;
|
||||||
|
|
||||||
|
$helper = new Helper();
|
||||||
|
|
||||||
|
return $helper->parseHttpRequest(function () {
|
||||||
|
throw new InvariantViolation("Shouldn't read from php://input for multipart/form-data request");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[] $postValue
|
||||||
|
* @return OperationParams|OperationParams[]
|
||||||
|
*/
|
||||||
|
private function parsePsrMultipartFormDataRequest($postValue)
|
||||||
|
{
|
||||||
|
$psrRequest = new PsrRequestStub();
|
||||||
|
$psrRequest->headers['content-type'] = ['multipart/form-data; boundary=----FormBoundary'];
|
||||||
|
$psrRequest->method = 'POST';
|
||||||
|
$psrRequest->parsedBody = $postValue;
|
||||||
|
|
||||||
|
$helper = new Helper();
|
||||||
|
|
||||||
|
return $helper->parsePsrRequest($psrRequest);
|
||||||
|
}
|
||||||
|
|
||||||
public function testParsesJSONRequest() : void
|
public function testParsesJSONRequest() : void
|
||||||
{
|
{
|
||||||
$query = '{my query}';
|
$query = '{my query}';
|
||||||
@ -101,11 +273,11 @@ class RequestParsingTest extends TestCase
|
|||||||
$body = [
|
$body = [
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'variables' => $variables,
|
'variables' => $variables,
|
||||||
'operationName' => $operation
|
'operationName' => $operation,
|
||||||
];
|
];
|
||||||
$parsed = [
|
$parsed = [
|
||||||
'raw' => $this->parseRawRequest('application/json', json_encode($body)),
|
'raw' => $this->parseRawRequest('application/json', json_encode($body)),
|
||||||
'psr' => $this->parsePsrRequest('application/json', json_encode($body))
|
'psr' => $this->parsePsrRequest('application/json', json_encode($body)),
|
||||||
];
|
];
|
||||||
foreach ($parsed as $method => $parsedBody) {
|
foreach ($parsed as $method => $parsedBody) {
|
||||||
$this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method);
|
$this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method);
|
||||||
@ -122,11 +294,11 @@ class RequestParsingTest extends TestCase
|
|||||||
$body = [
|
$body = [
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'variables' => json_encode($variables),
|
'variables' => json_encode($variables),
|
||||||
'operationName' => $operation
|
'operationName' => $operation,
|
||||||
];
|
];
|
||||||
$parsed = [
|
$parsed = [
|
||||||
'raw' => $this->parseRawRequest('application/json', json_encode($body)),
|
'raw' => $this->parseRawRequest('application/json', json_encode($body)),
|
||||||
'psr' => $this->parsePsrRequest('application/json', json_encode($body))
|
'psr' => $this->parsePsrRequest('application/json', json_encode($body)),
|
||||||
];
|
];
|
||||||
foreach ($parsed as $method => $parsedBody) {
|
foreach ($parsed as $method => $parsedBody) {
|
||||||
$this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method);
|
$this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method);
|
||||||
@ -143,7 +315,7 @@ class RequestParsingTest extends TestCase
|
|||||||
$body = [
|
$body = [
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'variables' => $variables,
|
'variables' => $variables,
|
||||||
'operationName' => $operation
|
'operationName' => $operation,
|
||||||
];
|
];
|
||||||
$parsed = [
|
$parsed = [
|
||||||
'raw' => $this->parseRawRequest('application/json', json_encode($body)),
|
'raw' => $this->parseRawRequest('application/json', json_encode($body)),
|
||||||
@ -161,23 +333,37 @@ class RequestParsingTest extends TestCase
|
|||||||
[
|
[
|
||||||
'query' => '{my query}',
|
'query' => '{my query}',
|
||||||
'variables' => ['test' => 1, 'test2' => 2],
|
'variables' => ['test' => 1, 'test2' => 2],
|
||||||
'operationName' => 'op'
|
'operationName' => 'op',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'queryId' => 'my-query-id',
|
'queryId' => 'my-query-id',
|
||||||
'variables' => ['test' => 1, 'test2' => 2],
|
'variables' => ['test' => 1, 'test2' => 2],
|
||||||
'operationName' => 'op2'
|
'operationName' => 'op2',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
$parsed = [
|
$parsed = [
|
||||||
'raw' => $this->parseRawRequest('application/json', json_encode($body)),
|
'raw' => $this->parseRawRequest('application/json', json_encode($body)),
|
||||||
'psr' => $this->parsePsrRequest('application/json', json_encode($body))
|
'psr' => $this->parsePsrRequest('application/json', json_encode($body)),
|
||||||
];
|
];
|
||||||
foreach ($parsed as $method => $parsedBody) {
|
foreach ($parsed as $method => $parsedBody) {
|
||||||
$this->assertInternalType('array', $parsedBody, $method);
|
$this->assertInternalType('array', $parsedBody, $method);
|
||||||
$this->assertCount(2, $parsedBody, $method);
|
$this->assertCount(2, $parsedBody, $method);
|
||||||
$this->assertValidOperationParams($parsedBody[0], $body[0]['query'], null, $body[0]['variables'], $body[0]['operationName'], $method);
|
$this->assertValidOperationParams(
|
||||||
$this->assertValidOperationParams($parsedBody[1], null, $body[1]['queryId'], $body[1]['variables'], $body[1]['operationName'], $method);
|
$parsedBody[0],
|
||||||
|
$body[0]['query'],
|
||||||
|
null,
|
||||||
|
$body[0]['variables'],
|
||||||
|
$body[0]['operationName'],
|
||||||
|
$method
|
||||||
|
);
|
||||||
|
$this->assertValidOperationParams(
|
||||||
|
$parsedBody[1],
|
||||||
|
null,
|
||||||
|
$body[1]['queryId'],
|
||||||
|
$body[1]['variables'],
|
||||||
|
$body[1]['operationName'],
|
||||||
|
$method
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,169 +458,13 @@ class RequestParsingTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectException(RequestError::class);
|
$this->expectException(RequestError::class);
|
||||||
$this->expectExceptionMessage('HTTP Method "PUT" is not supported');
|
$this->expectExceptionMessage('HTTP Method "PUT" is not supported');
|
||||||
$this->parseRawRequest('application/json', json_encode([]), "PUT");
|
$this->parseRawRequest('application/json', json_encode([]), 'PUT');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testFailsOnMethodsOtherThanPostOrGetPsr() : void
|
public function testFailsOnMethodsOtherThanPostOrGetPsr() : void
|
||||||
{
|
{
|
||||||
$this->expectException(RequestError::class);
|
$this->expectException(RequestError::class);
|
||||||
$this->expectExceptionMessage('HTTP Method "PUT" is not supported');
|
$this->expectExceptionMessage('HTTP Method "PUT" is not supported');
|
||||||
$this->parsePsrRequest('application/json', json_encode([]), "PUT");
|
$this->parsePsrRequest('application/json', json_encode([]), 'PUT');
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $contentType
|
|
||||||
* @param string $content
|
|
||||||
* @param $method
|
|
||||||
*
|
|
||||||
* @return OperationParams|OperationParams[]
|
|
||||||
*/
|
|
||||||
private function parseRawRequest($contentType, $content, $method = 'POST')
|
|
||||||
{
|
|
||||||
$_SERVER['CONTENT_TYPE'] = $contentType;
|
|
||||||
$_SERVER['REQUEST_METHOD'] = $method;
|
|
||||||
|
|
||||||
$helper = new Helper();
|
|
||||||
return $helper->parseHttpRequest(function() use ($content) {
|
|
||||||
return $content;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $contentType
|
|
||||||
* @param string $content
|
|
||||||
* @param $method
|
|
||||||
*
|
|
||||||
* @return OperationParams|OperationParams[]
|
|
||||||
*/
|
|
||||||
private function parsePsrRequest($contentType, $content, $method = 'POST')
|
|
||||||
{
|
|
||||||
$psrRequestBody = new PsrStreamStub();
|
|
||||||
$psrRequestBody->content = $content;
|
|
||||||
|
|
||||||
$psrRequest = new PsrRequestStub();
|
|
||||||
$psrRequest->headers['content-type'] = [$contentType];
|
|
||||||
$psrRequest->method = $method;
|
|
||||||
$psrRequest->body = $psrRequestBody;
|
|
||||||
|
|
||||||
if ($contentType === 'application/json') {
|
|
||||||
$parsedBody = json_decode($content, true);
|
|
||||||
$parsedBody = $parsedBody === false ? null : $parsedBody;
|
|
||||||
} else {
|
|
||||||
$parsedBody = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$psrRequest->parsedBody = $parsedBody;
|
|
||||||
|
|
||||||
$helper = new Helper();
|
|
||||||
return $helper->parsePsrRequest($psrRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $postValue
|
|
||||||
* @return OperationParams|OperationParams[]
|
|
||||||
*/
|
|
||||||
private function parseRawFormUrlencodedRequest($postValue)
|
|
||||||
{
|
|
||||||
$_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
|
|
||||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
|
||||||
$_POST = $postValue;
|
|
||||||
|
|
||||||
$helper = new Helper();
|
|
||||||
return $helper->parseHttpRequest(function() {
|
|
||||||
throw new InvariantViolation("Shouldn't read from php://input for urlencoded request");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $postValue
|
|
||||||
* @return array|Helper
|
|
||||||
*/
|
|
||||||
private function parsePsrFormUrlEncodedRequest($postValue)
|
|
||||||
{
|
|
||||||
$psrRequest = new PsrRequestStub();
|
|
||||||
$psrRequest->headers['content-type'] = ['application/x-www-form-urlencoded'];
|
|
||||||
$psrRequest->method = 'POST';
|
|
||||||
$psrRequest->parsedBody = $postValue;
|
|
||||||
|
|
||||||
$helper = new Helper();
|
|
||||||
return $helper->parsePsrRequest($psrRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $postValue
|
|
||||||
* @return OperationParams|OperationParams[]
|
|
||||||
*/
|
|
||||||
private function parseRawMultipartFormDataRequest($postValue)
|
|
||||||
{
|
|
||||||
$_SERVER['CONTENT_TYPE'] = 'multipart/form-data; boundary=----FormBoundary';
|
|
||||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
|
||||||
$_POST = $postValue;
|
|
||||||
|
|
||||||
$helper = new Helper();
|
|
||||||
return $helper->parseHttpRequest(function() {
|
|
||||||
throw new InvariantViolation("Shouldn't read from php://input for multipart/form-data request");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $postValue
|
|
||||||
* @return array|Helper
|
|
||||||
*/
|
|
||||||
private function parsePsrMultipartFormDataRequest($postValue)
|
|
||||||
{
|
|
||||||
$psrRequest = new PsrRequestStub();
|
|
||||||
$psrRequest->headers['content-type'] = ['multipart/form-data; boundary=----FormBoundary'];
|
|
||||||
$psrRequest->method = 'POST';
|
|
||||||
$psrRequest->parsedBody = $postValue;
|
|
||||||
|
|
||||||
$helper = new Helper();
|
|
||||||
return $helper->parsePsrRequest($psrRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $getValue
|
|
||||||
* @return OperationParams
|
|
||||||
*/
|
|
||||||
private function parseRawGetRequest($getValue)
|
|
||||||
{
|
|
||||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
|
||||||
$_GET = $getValue;
|
|
||||||
|
|
||||||
$helper = new Helper();
|
|
||||||
return $helper->parseHttpRequest(function() {
|
|
||||||
throw new InvariantViolation("Shouldn't read from php://input for urlencoded request");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $getValue
|
|
||||||
* @return array|Helper
|
|
||||||
*/
|
|
||||||
private function parsePsrGetRequest($getValue)
|
|
||||||
{
|
|
||||||
$psrRequest = new PsrRequestStub();
|
|
||||||
$psrRequest->method = 'GET';
|
|
||||||
$psrRequest->queryParams = $getValue;
|
|
||||||
|
|
||||||
$helper = new Helper();
|
|
||||||
return $helper->parsePsrRequest($psrRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param OperationParams $params
|
|
||||||
* @param string $query
|
|
||||||
* @param string $queryId
|
|
||||||
* @param array $variables
|
|
||||||
* @param string $operation
|
|
||||||
*/
|
|
||||||
private function assertValidOperationParams($params, $query, $queryId = null, $variables = null, $operation = null, $message = '')
|
|
||||||
{
|
|
||||||
$this->assertInstanceOf(OperationParams::class, $params, $message);
|
|
||||||
|
|
||||||
$this->assertSame($query, $params->query, $message);
|
|
||||||
$this->assertSame($queryId, $params->queryId, $message);
|
|
||||||
$this->assertSame($variables, $params->variables, $message);
|
|
||||||
$this->assertSame($operation, $params->operation, $message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Server;
|
namespace GraphQL\Tests\Server;
|
||||||
|
|
||||||
use GraphQL\Server\Helper;
|
use GraphQL\Server\Helper;
|
||||||
@ -22,6 +25,13 @@ class RequestValidationTest extends TestCase
|
|||||||
$this->assertValid($parsedBody);
|
$this->assertValid($parsedBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function assertValid($parsedRequest)
|
||||||
|
{
|
||||||
|
$helper = new Helper();
|
||||||
|
$errors = $helper->validateOperationParams($parsedRequest);
|
||||||
|
$this->assertEmpty($errors, isset($errors[0]) ? $errors[0]->getMessage() : '');
|
||||||
|
}
|
||||||
|
|
||||||
public function testRequestWithQueryIdShouldValidate() : void
|
public function testRequestWithQueryIdShouldValidate() : void
|
||||||
{
|
{
|
||||||
$queryId = 'some-query-id';
|
$queryId = 'some-query-id';
|
||||||
@ -50,6 +60,17 @@ class RequestValidationTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function assertInputError($parsedRequest, $expectedMessage)
|
||||||
|
{
|
||||||
|
$helper = new Helper();
|
||||||
|
$errors = $helper->validateOperationParams($parsedRequest);
|
||||||
|
if (! empty($errors[0])) {
|
||||||
|
$this->assertEquals($expectedMessage, $errors[0]->getMessage());
|
||||||
|
} else {
|
||||||
|
$this->fail('Expected error not returned');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function testFailsWhenBothQueryAndQueryIdArePresent() : void
|
public function testFailsWhenBothQueryAndQueryIdArePresent() : void
|
||||||
{
|
{
|
||||||
$parsedBody = OperationParams::create([
|
$parsedBody = OperationParams::create([
|
||||||
@ -66,7 +87,7 @@ class RequestValidationTest extends TestCase
|
|||||||
public function testFailsWhenQueryParameterIsNotString() : void
|
public function testFailsWhenQueryParameterIsNotString() : void
|
||||||
{
|
{
|
||||||
$parsedBody = OperationParams::create([
|
$parsedBody = OperationParams::create([
|
||||||
'query' => ['t' => '{my query}']
|
'query' => ['t' => '{my query}'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertInputError(
|
$this->assertInputError(
|
||||||
@ -78,7 +99,7 @@ class RequestValidationTest extends TestCase
|
|||||||
public function testFailsWhenQueryIdParameterIsNotString() : void
|
public function testFailsWhenQueryIdParameterIsNotString() : void
|
||||||
{
|
{
|
||||||
$parsedBody = OperationParams::create([
|
$parsedBody = OperationParams::create([
|
||||||
'queryId' => ['t' => '{my query}']
|
'queryId' => ['t' => '{my query}'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertInputError(
|
$this->assertInputError(
|
||||||
@ -91,7 +112,7 @@ class RequestValidationTest extends TestCase
|
|||||||
{
|
{
|
||||||
$parsedBody = OperationParams::create([
|
$parsedBody = OperationParams::create([
|
||||||
'query' => '{my query}',
|
'query' => '{my query}',
|
||||||
'operationName' => []
|
'operationName' => [],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertInputError(
|
$this->assertInputError(
|
||||||
@ -108,14 +129,14 @@ class RequestValidationTest extends TestCase
|
|||||||
$query = '{my q}';
|
$query = '{my q}';
|
||||||
$parsedBody = OperationParams::create([
|
$parsedBody = OperationParams::create([
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'variables' => null
|
'variables' => null,
|
||||||
]);
|
]);
|
||||||
$this->assertValid($parsedBody);
|
$this->assertValid($parsedBody);
|
||||||
|
|
||||||
$variables = "";
|
$variables = '';
|
||||||
$parsedBody = OperationParams::create([
|
$parsedBody = OperationParams::create([
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'variables' => $variables
|
'variables' => $variables,
|
||||||
]);
|
]);
|
||||||
$this->assertValid($parsedBody);
|
$this->assertValid($parsedBody);
|
||||||
}
|
}
|
||||||
@ -124,7 +145,7 @@ class RequestValidationTest extends TestCase
|
|||||||
{
|
{
|
||||||
$parsedBody = OperationParams::create([
|
$parsedBody = OperationParams::create([
|
||||||
'query' => '{my query}',
|
'query' => '{my query}',
|
||||||
'variables' => 0
|
'variables' => 0,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertInputError(
|
$this->assertInputError(
|
||||||
@ -132,22 +153,4 @@ class RequestValidationTest extends TestCase
|
|||||||
'GraphQL Request parameter "variables" must be object or JSON string parsed to object, but got 0'
|
'GraphQL Request parameter "variables" must be object or JSON string parsed to object, but got 0'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function assertValid($parsedRequest)
|
|
||||||
{
|
|
||||||
$helper = new Helper();
|
|
||||||
$errors = $helper->validateOperationParams($parsedRequest);
|
|
||||||
$this->assertEmpty($errors, isset($errors[0]) ? $errors[0]->getMessage() : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
private function assertInputError($parsedRequest, $expectedMessage)
|
|
||||||
{
|
|
||||||
$helper = new Helper();
|
|
||||||
$errors = $helper->validateOperationParams($parsedRequest);
|
|
||||||
if (!empty($errors[0])) {
|
|
||||||
$this->assertEquals($expectedMessage, $errors[0]->getMessage());
|
|
||||||
} else {
|
|
||||||
$this->fail('Expected error not returned');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Server;
|
namespace GraphQL\Tests\Server;
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
|
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Server\ServerConfig;
|
use GraphQL\Server\ServerConfig;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class ServerConfigTest extends TestCase
|
class ServerConfigTest extends TestCase
|
||||||
@ -14,17 +17,17 @@ class ServerConfigTest extends TestCase
|
|||||||
public function testDefaults() : void
|
public function testDefaults() : void
|
||||||
{
|
{
|
||||||
$config = ServerConfig::create();
|
$config = ServerConfig::create();
|
||||||
$this->assertEquals(null, $config->getSchema());
|
$this->assertNull($config->getSchema());
|
||||||
$this->assertEquals(null, $config->getContext());
|
$this->assertNull($config->getContext());
|
||||||
$this->assertEquals(null, $config->getRootValue());
|
$this->assertNull($config->getRootValue());
|
||||||
$this->assertEquals(null, $config->getErrorFormatter());
|
$this->assertNull($config->getErrorFormatter());
|
||||||
$this->assertEquals(null, $config->getErrorsHandler());
|
$this->assertNull($config->getErrorsHandler());
|
||||||
$this->assertEquals(null, $config->getPromiseAdapter());
|
$this->assertNull($config->getPromiseAdapter());
|
||||||
$this->assertEquals(null, $config->getValidationRules());
|
$this->assertNull($config->getValidationRules());
|
||||||
$this->assertEquals(null, $config->getFieldResolver());
|
$this->assertNull($config->getFieldResolver());
|
||||||
$this->assertEquals(null, $config->getPersistentQueryLoader());
|
$this->assertNull($config->getPersistentQueryLoader());
|
||||||
$this->assertEquals(false, $config->getDebug());
|
$this->assertFalse($config->getDebug());
|
||||||
$this->assertEquals(false, $config->getQueryBatching());
|
$this->assertFalse($config->getQueryBatching());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAllowsSettingSchema() : void
|
public function testAllowsSettingSchema() : void
|
||||||
@ -70,7 +73,8 @@ class ServerConfigTest extends TestCase
|
|||||||
{
|
{
|
||||||
$config = ServerConfig::create();
|
$config = ServerConfig::create();
|
||||||
|
|
||||||
$formatter = function() {};
|
$formatter = function () {
|
||||||
|
};
|
||||||
$config->setErrorFormatter($formatter);
|
$config->setErrorFormatter($formatter);
|
||||||
$this->assertSame($formatter, $config->getErrorFormatter());
|
$this->assertSame($formatter, $config->getErrorFormatter());
|
||||||
|
|
||||||
@ -83,7 +87,8 @@ class ServerConfigTest extends TestCase
|
|||||||
{
|
{
|
||||||
$config = ServerConfig::create();
|
$config = ServerConfig::create();
|
||||||
|
|
||||||
$handler = function() {};
|
$handler = function () {
|
||||||
|
};
|
||||||
$config->setErrorsHandler($handler);
|
$config->setErrorsHandler($handler);
|
||||||
$this->assertSame($handler, $config->getErrorsHandler());
|
$this->assertSame($handler, $config->getErrorsHandler());
|
||||||
|
|
||||||
@ -113,11 +118,17 @@ class ServerConfigTest extends TestCase
|
|||||||
$config->setValidationRules($rules);
|
$config->setValidationRules($rules);
|
||||||
$this->assertSame($rules, $config->getValidationRules());
|
$this->assertSame($rules, $config->getValidationRules());
|
||||||
|
|
||||||
$rules = [function() {}];
|
$rules = [function () {
|
||||||
|
},
|
||||||
|
];
|
||||||
$config->setValidationRules($rules);
|
$config->setValidationRules($rules);
|
||||||
$this->assertSame($rules, $config->getValidationRules());
|
$this->assertSame($rules, $config->getValidationRules());
|
||||||
|
|
||||||
$rules = function() {return [function() {}];};
|
$rules = function () {
|
||||||
|
return [function () {
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
$config->setValidationRules($rules);
|
$config->setValidationRules($rules);
|
||||||
$this->assertSame($rules, $config->getValidationRules());
|
$this->assertSame($rules, $config->getValidationRules());
|
||||||
}
|
}
|
||||||
@ -126,7 +137,8 @@ class ServerConfigTest extends TestCase
|
|||||||
{
|
{
|
||||||
$config = ServerConfig::create();
|
$config = ServerConfig::create();
|
||||||
|
|
||||||
$resolver = function() {};
|
$resolver = function () {
|
||||||
|
};
|
||||||
$config->setFieldResolver($resolver);
|
$config->setFieldResolver($resolver);
|
||||||
$this->assertSame($resolver, $config->getFieldResolver());
|
$this->assertSame($resolver, $config->getFieldResolver());
|
||||||
|
|
||||||
@ -139,7 +151,8 @@ class ServerConfigTest extends TestCase
|
|||||||
{
|
{
|
||||||
$config = ServerConfig::create();
|
$config = ServerConfig::create();
|
||||||
|
|
||||||
$loader = function() {};
|
$loader = function () {
|
||||||
|
};
|
||||||
$config->setPersistentQueryLoader($loader);
|
$config->setPersistentQueryLoader($loader);
|
||||||
$this->assertSame($loader, $config->getPersistentQueryLoader());
|
$this->assertSame($loader, $config->getPersistentQueryLoader());
|
||||||
|
|
||||||
@ -153,25 +166,30 @@ class ServerConfigTest extends TestCase
|
|||||||
$config = ServerConfig::create();
|
$config = ServerConfig::create();
|
||||||
|
|
||||||
$config->setDebug(true);
|
$config->setDebug(true);
|
||||||
$this->assertSame(true, $config->getDebug());
|
$this->assertTrue($config->getDebug());
|
||||||
|
|
||||||
$config->setDebug(false);
|
$config->setDebug(false);
|
||||||
$this->assertSame(false, $config->getDebug());
|
$this->assertFalse($config->getDebug());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAcceptsArray() : void
|
public function testAcceptsArray() : void
|
||||||
{
|
{
|
||||||
$arr = [
|
$arr = [
|
||||||
'schema' => new \GraphQL\Type\Schema([
|
'schema' => new Schema([
|
||||||
'query' => new ObjectType(['name' => 't', 'fields' => ['a' => Type::string()]])
|
'query' => new ObjectType(['name' => 't', 'fields' => ['a' => Type::string()]]),
|
||||||
]),
|
]),
|
||||||
'context' => new \stdClass(),
|
'context' => new \stdClass(),
|
||||||
'rootValue' => new \stdClass(),
|
'rootValue' => new \stdClass(),
|
||||||
'errorFormatter' => function() {},
|
'errorFormatter' => function () {
|
||||||
|
},
|
||||||
'promiseAdapter' => new SyncPromiseAdapter(),
|
'promiseAdapter' => new SyncPromiseAdapter(),
|
||||||
'validationRules' => [function() {}],
|
'validationRules' => [function () {
|
||||||
'fieldResolver' => function() {},
|
},
|
||||||
'persistentQueryLoader' => function() {},
|
],
|
||||||
|
'fieldResolver' => function () {
|
||||||
|
},
|
||||||
|
'persistentQueryLoader' => function () {
|
||||||
|
},
|
||||||
'debug' => true,
|
'debug' => true,
|
||||||
'queryBatching' => true,
|
'queryBatching' => true,
|
||||||
];
|
];
|
||||||
@ -186,15 +204,13 @@ class ServerConfigTest extends TestCase
|
|||||||
$this->assertSame($arr['validationRules'], $config->getValidationRules());
|
$this->assertSame($arr['validationRules'], $config->getValidationRules());
|
||||||
$this->assertSame($arr['fieldResolver'], $config->getFieldResolver());
|
$this->assertSame($arr['fieldResolver'], $config->getFieldResolver());
|
||||||
$this->assertSame($arr['persistentQueryLoader'], $config->getPersistentQueryLoader());
|
$this->assertSame($arr['persistentQueryLoader'], $config->getPersistentQueryLoader());
|
||||||
$this->assertSame(true, $config->getDebug());
|
$this->assertTrue($config->getDebug());
|
||||||
$this->assertSame(true, $config->getQueryBatching());
|
$this->assertTrue($config->getQueryBatching());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testThrowsOnInvalidArrayKey() : void
|
public function testThrowsOnInvalidArrayKey() : void
|
||||||
{
|
{
|
||||||
$arr = [
|
$arr = ['missingKey' => 'value'];
|
||||||
'missingKey' => 'value'
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->expectException(InvariantViolation::class);
|
$this->expectException(InvariantViolation::class);
|
||||||
$this->expectExceptionMessage('Unknown server config option "missingKey"');
|
$this->expectExceptionMessage('Unknown server config option "missingKey"');
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Server;
|
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Server;
|
||||||
|
|
||||||
use GraphQL\Deferred;
|
use GraphQL\Deferred;
|
||||||
use GraphQL\Error\ClientAware;
|
use GraphQL\Error\ClientAware;
|
||||||
@ -9,6 +11,10 @@ use GraphQL\Type\Definition\ObjectType;
|
|||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function trigger_error;
|
||||||
|
use const E_USER_DEPRECATED;
|
||||||
|
use const E_USER_NOTICE;
|
||||||
|
use const E_USER_WARNING;
|
||||||
|
|
||||||
abstract class ServerTestCase extends TestCase
|
abstract class ServerTestCase extends TestCase
|
||||||
{
|
{
|
||||||
@ -20,20 +26,21 @@ abstract class ServerTestCase extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'f1' => [
|
'f1' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function($root, $args, $context, $info) {
|
'resolve' => function ($root, $args, $context, $info) {
|
||||||
return $info->fieldName;
|
return $info->fieldName;
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'fieldWithPhpError' => [
|
'fieldWithPhpError' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function($root, $args, $context, $info) {
|
'resolve' => function ($root, $args, $context, $info) {
|
||||||
trigger_error('deprecated', E_USER_DEPRECATED);
|
trigger_error('deprecated', E_USER_DEPRECATED);
|
||||||
trigger_error('notice', E_USER_NOTICE);
|
trigger_error('notice', E_USER_NOTICE);
|
||||||
trigger_error('warning', E_USER_WARNING);
|
trigger_error('warning', E_USER_WARNING);
|
||||||
$a = [];
|
$a = [];
|
||||||
$a['test']; // should produce PHP notice
|
$a['test']; // should produce PHP notice
|
||||||
|
|
||||||
return $info->fieldName;
|
return $info->fieldName;
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'fieldWithSafeException' => [
|
'fieldWithSafeException' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
@ -49,38 +56,39 @@ abstract class ServerTestCase extends TestCase
|
|||||||
],
|
],
|
||||||
'testContextAndRootValue' => [
|
'testContextAndRootValue' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'resolve' => function($root, $args, $context, $info) {
|
'resolve' => function ($root, $args, $context, $info) {
|
||||||
$context->testedRootValue = $root;
|
$context->testedRootValue = $root;
|
||||||
|
|
||||||
return $info->fieldName;
|
return $info->fieldName;
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'fieldWithArg' => [
|
'fieldWithArg' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'args' => [
|
'args' => [
|
||||||
'arg' => [
|
'arg' => [
|
||||||
'type' => Type::nonNull(Type::string())
|
'type' => Type::nonNull(Type::string()),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'resolve' => function($root, $args) {
|
'resolve' => function ($root, $args) {
|
||||||
return $args['arg'];
|
return $args['arg'];
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'dfd' => [
|
'dfd' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'args' => [
|
'args' => [
|
||||||
'num' => [
|
'num' => [
|
||||||
'type' => Type::nonNull(Type::int())
|
'type' => Type::nonNull(Type::int()),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'resolve' => function($root, $args, $context) {
|
'resolve' => function ($root, $args, $context) {
|
||||||
$context['buffer']($args['num']);
|
$context['buffer']($args['num']);
|
||||||
|
|
||||||
return new Deferred(function() use ($args, $context) {
|
return new Deferred(function () use ($args, $context) {
|
||||||
return $context['load']($args['num']);
|
return $context['load']($args['num']);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'mutation' => new ObjectType([
|
'mutation' => new ObjectType([
|
||||||
'name' => 'Mutation',
|
'name' => 'Mutation',
|
||||||
@ -89,13 +97,14 @@ abstract class ServerTestCase extends TestCase
|
|||||||
'type' => new ObjectType([
|
'type' => new ObjectType([
|
||||||
'name' => 'TestMutation',
|
'name' => 'TestMutation',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'result' => Type::string()
|
'result' => Type::string(),
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $schema;
|
return $schema;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Server;
|
namespace GraphQL\Tests\Server;
|
||||||
|
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
@ -6,13 +9,11 @@ use GraphQL\Server\Helper;
|
|||||||
use GraphQL\Server\ServerConfig;
|
use GraphQL\Server\ServerConfig;
|
||||||
use GraphQL\Server\StandardServer;
|
use GraphQL\Server\StandardServer;
|
||||||
use GraphQL\Tests\Server\Psr7\PsrRequestStub;
|
use GraphQL\Tests\Server\Psr7\PsrRequestStub;
|
||||||
use GraphQL\Tests\Server\Psr7\PsrStreamStub;
|
use function json_encode;
|
||||||
|
|
||||||
class StandardServerTest extends ServerTestCase
|
class StandardServerTest extends ServerTestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var ServerConfig */
|
||||||
* @var ServerConfig
|
|
||||||
*/
|
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -24,88 +25,82 @@ class StandardServerTest extends ServerTestCase
|
|||||||
|
|
||||||
public function testSimpleRequestExecutionWithOutsideParsing() : void
|
public function testSimpleRequestExecutionWithOutsideParsing() : void
|
||||||
{
|
{
|
||||||
$body = json_encode([
|
$body = json_encode(['query' => '{f1}']);
|
||||||
'query' => '{f1}'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$parsedBody = $this->parseRawRequest('application/json', $body);
|
$parsedBody = $this->parseRawRequest('application/json', $body);
|
||||||
$server = new StandardServer($this->config);
|
$server = new StandardServer($this->config);
|
||||||
|
|
||||||
$result = $server->executeRequest($parsedBody);
|
$result = $server->executeRequest($parsedBody);
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => ['f1' => 'f1'],
|
||||||
'f1' => 'f1',
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expected, $result->toArray(true));
|
$this->assertEquals($expected, $result->toArray(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSimplePsrRequestExecution() : void
|
|
||||||
{
|
|
||||||
$body = [
|
|
||||||
'query' => '{f1}'
|
|
||||||
];
|
|
||||||
|
|
||||||
$expected = [
|
|
||||||
'data' => [
|
|
||||||
'f1' => 'f1'
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->preparePsrRequest('application/json', $body);
|
|
||||||
$this->assertPsrRequestEquals($expected, $request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testMultipleOperationPsrRequestExecution() : void
|
|
||||||
{
|
|
||||||
$body = [
|
|
||||||
'query' => 'query firstOp {fieldWithPhpError} query secondOp {f1}',
|
|
||||||
'operationName' => 'secondOp'
|
|
||||||
];
|
|
||||||
|
|
||||||
$expected = [
|
|
||||||
'data' => [
|
|
||||||
'f1' => 'f1'
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->preparePsrRequest('application/json', $body);
|
|
||||||
$this->assertPsrRequestEquals($expected, $request);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function executePsrRequest($psrRequest)
|
|
||||||
{
|
|
||||||
$server = new StandardServer($this->config);
|
|
||||||
$result = $server->executePsrRequest($psrRequest);
|
|
||||||
$this->assertInstanceOf(ExecutionResult::class, $result);
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function assertPsrRequestEquals($expected, $request)
|
|
||||||
{
|
|
||||||
$result = $this->executePsrRequest($request);
|
|
||||||
$this->assertArraySubset($expected, $result->toArray(true));
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function preparePsrRequest($contentType, $parsedBody)
|
|
||||||
{
|
|
||||||
$psrRequest = new PsrRequestStub();
|
|
||||||
$psrRequest->headers['content-type'] = [$contentType];
|
|
||||||
$psrRequest->method = 'POST';
|
|
||||||
$psrRequest->parsedBody = $parsedBody;
|
|
||||||
return $psrRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function parseRawRequest($contentType, $content, $method = 'POST')
|
private function parseRawRequest($contentType, $content, $method = 'POST')
|
||||||
{
|
{
|
||||||
$_SERVER['CONTENT_TYPE'] = $contentType;
|
$_SERVER['CONTENT_TYPE'] = $contentType;
|
||||||
$_SERVER['REQUEST_METHOD'] = $method;
|
$_SERVER['REQUEST_METHOD'] = $method;
|
||||||
|
|
||||||
$helper = new Helper();
|
$helper = new Helper();
|
||||||
return $helper->parseHttpRequest(function() use ($content) {
|
|
||||||
|
return $helper->parseHttpRequest(function () use ($content) {
|
||||||
return $content;
|
return $content;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSimplePsrRequestExecution() : void
|
||||||
|
{
|
||||||
|
$body = ['query' => '{f1}'];
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
'data' => ['f1' => 'f1'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$request = $this->preparePsrRequest('application/json', $body);
|
||||||
|
$this->assertPsrRequestEquals($expected, $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function preparePsrRequest($contentType, $parsedBody)
|
||||||
|
{
|
||||||
|
$psrRequest = new PsrRequestStub();
|
||||||
|
$psrRequest->headers['content-type'] = [$contentType];
|
||||||
|
$psrRequest->method = 'POST';
|
||||||
|
$psrRequest->parsedBody = $parsedBody;
|
||||||
|
|
||||||
|
return $psrRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function assertPsrRequestEquals($expected, $request)
|
||||||
|
{
|
||||||
|
$result = $this->executePsrRequest($request);
|
||||||
|
$this->assertArraySubset($expected, $result->toArray(true));
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function executePsrRequest($psrRequest)
|
||||||
|
{
|
||||||
|
$server = new StandardServer($this->config);
|
||||||
|
$result = $server->executePsrRequest($psrRequest);
|
||||||
|
$this->assertInstanceOf(ExecutionResult::class, $result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMultipleOperationPsrRequestExecution() : void
|
||||||
|
{
|
||||||
|
$body = [
|
||||||
|
'query' => 'query firstOp {fieldWithPhpError} query secondOp {f1}',
|
||||||
|
'operationName' => 'secondOp',
|
||||||
|
];
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
'data' => ['f1' => 'f1'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$request = $this->preparePsrRequest('application/json', $body);
|
||||||
|
$this->assertPsrRequestEquals($expected, $request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,41 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests;
|
namespace GraphQL\Tests;
|
||||||
|
|
||||||
|
use function array_map;
|
||||||
|
|
||||||
class StarWarsData
|
class StarWarsData
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Helper function to get a character by ID.
|
||||||
|
*/
|
||||||
|
public static function getCharacter($id)
|
||||||
|
{
|
||||||
|
$humans = self::humans();
|
||||||
|
$droids = self::droids();
|
||||||
|
if (isset($humans[$id])) {
|
||||||
|
return $humans[$id];
|
||||||
|
}
|
||||||
|
if (isset($droids[$id])) {
|
||||||
|
return $droids[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function humans()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'1000' => self::luke(),
|
||||||
|
'1001' => self::vader(),
|
||||||
|
'1002' => self::han(),
|
||||||
|
'1003' => self::leia(),
|
||||||
|
'1004' => self::tarkin(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
private static function luke()
|
private static function luke()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@ -56,14 +89,11 @@ class StarWarsData
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
static function humans()
|
public static function droids()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'1000' => self::luke(),
|
'2000' => self::threepio(),
|
||||||
'1001' => self::vader(),
|
'2001' => self::artoo(),
|
||||||
'1002' => self::han(),
|
|
||||||
'1003' => self::leia(),
|
|
||||||
'1004' => self::tarkin(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +112,7 @@ class StarWarsData
|
|||||||
* We export artoo directly because the schema returns him
|
* We export artoo directly because the schema returns him
|
||||||
* from a root field, and hence needs to reference him.
|
* from a root field, and hence needs to reference him.
|
||||||
*/
|
*/
|
||||||
static function artoo()
|
private static function artoo()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|
||||||
@ -94,69 +124,48 @@ class StarWarsData
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
static function droids()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'2000' => self::threepio(),
|
|
||||||
'2001' => self::artoo(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to get a character by ID.
|
|
||||||
*/
|
|
||||||
static function getCharacter($id)
|
|
||||||
{
|
|
||||||
$humans = self::humans();
|
|
||||||
$droids = self::droids();
|
|
||||||
if (isset($humans[$id])) {
|
|
||||||
return $humans[$id];
|
|
||||||
}
|
|
||||||
if (isset($droids[$id])) {
|
|
||||||
return $droids[$id];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows us to query for a character's friends.
|
* Allows us to query for a character's friends.
|
||||||
*/
|
*/
|
||||||
static function getFriends($character)
|
public static function getFriends($character)
|
||||||
{
|
{
|
||||||
return array_map([__CLASS__, 'getCharacter'], $character['friends']);
|
return array_map([__CLASS__, 'getCharacter'], $character['friends']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $episode
|
* @param int $episode
|
||||||
* @return array
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
static function getHero($episode)
|
public static function getHero($episode)
|
||||||
{
|
{
|
||||||
if ($episode === 5) {
|
if ($episode === 5) {
|
||||||
// Luke is the hero of Episode V.
|
// Luke is the hero of Episode V.
|
||||||
return self::luke();
|
return self::luke();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Artoo is the hero otherwise.
|
// Artoo is the hero otherwise.
|
||||||
return self::artoo();
|
return self::artoo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $id
|
* @param string $id
|
||||||
* @return mixed|null
|
* @return mixed|null
|
||||||
*/
|
*/
|
||||||
static function getHuman($id)
|
public static function getHuman($id)
|
||||||
{
|
{
|
||||||
$humans = self::humans();
|
$humans = self::humans();
|
||||||
return isset($humans[$id]) ? $humans[$id] : null;
|
|
||||||
|
return $humans[$id] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $id
|
* @param string $id
|
||||||
* @return mixed|null
|
* @return mixed|null
|
||||||
*/
|
*/
|
||||||
static function getDroid($id)
|
public static function getDroid($id)
|
||||||
{
|
{
|
||||||
$droids = self::droids();
|
$droids = self::droids();
|
||||||
return isset($droids[$id]) ? $droids[$id] : null;
|
|
||||||
|
return $droids[$id] ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests;
|
namespace GraphQL\Tests;
|
||||||
|
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
@ -44,12 +47,20 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
['name' => '__EnumValue'],
|
['name' => '__EnumValue'],
|
||||||
['name' => '__Directive'],
|
['name' => '__Directive'],
|
||||||
['name' => '__DirectiveLocation'],
|
['name' => '__DirectiveLocation'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to test a query and the expected response.
|
||||||
|
*/
|
||||||
|
private function assertValidQuery($query, $expected) : void
|
||||||
|
{
|
||||||
|
$this->assertEquals(['data' => $expected], GraphQL::executeQuery(StarWarsSchema::build(), $query)->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Allows querying the schema for query type')
|
* @see it('Allows querying the schema for query type')
|
||||||
*/
|
*/
|
||||||
@ -66,10 +77,8 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
';
|
';
|
||||||
$expected = [
|
$expected = [
|
||||||
'__schema' => [
|
'__schema' => [
|
||||||
'queryType' => [
|
'queryType' => ['name' => 'Query'],
|
||||||
'name' => 'Query'
|
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
@ -87,9 +96,7 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
}
|
}
|
||||||
';
|
';
|
||||||
$expected = [
|
$expected = [
|
||||||
'__type' => [
|
'__type' => ['name' => 'Droid'],
|
||||||
'name' => 'Droid'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
@ -110,8 +117,8 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'__type' => [
|
'__type' => [
|
||||||
'name' => 'Droid',
|
'name' => 'Droid',
|
||||||
'kind' => 'OBJECT'
|
'kind' => 'OBJECT',
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
@ -132,8 +139,8 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'__type' => [
|
'__type' => [
|
||||||
'name' => 'Character',
|
'name' => 'Character',
|
||||||
'kind' => 'INTERFACE'
|
'kind' => 'INTERFACE',
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
@ -165,46 +172,46 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
'name' => 'id',
|
'name' => 'id',
|
||||||
'type' => [
|
'type' => [
|
||||||
'name' => null,
|
'name' => null,
|
||||||
'kind' => 'NON_NULL'
|
'kind' => 'NON_NULL',
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'name',
|
'name' => 'name',
|
||||||
'type' => [
|
'type' => [
|
||||||
'name' => 'String',
|
'name' => 'String',
|
||||||
'kind' => 'SCALAR'
|
'kind' => 'SCALAR',
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'friends',
|
'name' => 'friends',
|
||||||
'type' => [
|
'type' => [
|
||||||
'name' => null,
|
'name' => null,
|
||||||
'kind' => 'LIST'
|
'kind' => 'LIST',
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'appearsIn',
|
'name' => 'appearsIn',
|
||||||
'type' => [
|
'type' => [
|
||||||
'name' => null,
|
'name' => null,
|
||||||
'kind' => 'LIST'
|
'kind' => 'LIST',
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'secretBackstory',
|
'name' => 'secretBackstory',
|
||||||
'type' => [
|
'type' => [
|
||||||
'name' => 'String',
|
'name' => 'String',
|
||||||
'kind' => 'SCALAR'
|
'kind' => 'SCALAR',
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'primaryFunction',
|
'name' => 'primaryFunction',
|
||||||
'type' => [
|
'type' => [
|
||||||
'name' => 'String',
|
'name' => 'String',
|
||||||
'kind' => 'SCALAR'
|
'kind' => 'SCALAR',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
@ -243,17 +250,17 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
'kind' => 'NON_NULL',
|
'kind' => 'NON_NULL',
|
||||||
'ofType' => [
|
'ofType' => [
|
||||||
'name' => 'String',
|
'name' => 'String',
|
||||||
'kind' => 'SCALAR'
|
'kind' => 'SCALAR',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'name',
|
'name' => 'name',
|
||||||
'type' => [
|
'type' => [
|
||||||
'name' => 'String',
|
'name' => 'String',
|
||||||
'kind' => 'SCALAR',
|
'kind' => 'SCALAR',
|
||||||
'ofType' => null
|
'ofType' => null,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'friends',
|
'name' => 'friends',
|
||||||
@ -262,9 +269,9 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
'kind' => 'LIST',
|
'kind' => 'LIST',
|
||||||
'ofType' => [
|
'ofType' => [
|
||||||
'name' => 'Character',
|
'name' => 'Character',
|
||||||
'kind' => 'INTERFACE'
|
'kind' => 'INTERFACE',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'appearsIn',
|
'name' => 'appearsIn',
|
||||||
@ -273,28 +280,28 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
'kind' => 'LIST',
|
'kind' => 'LIST',
|
||||||
'ofType' => [
|
'ofType' => [
|
||||||
'name' => 'Episode',
|
'name' => 'Episode',
|
||||||
'kind' => 'ENUM'
|
'kind' => 'ENUM',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'secretBackstory',
|
'name' => 'secretBackstory',
|
||||||
'type' => [
|
'type' => [
|
||||||
'name' => 'String',
|
'name' => 'String',
|
||||||
'kind' => 'SCALAR',
|
'kind' => 'SCALAR',
|
||||||
'ofType' => null
|
'ofType' => null,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'primaryFunction',
|
'name' => 'primaryFunction',
|
||||||
'type' => [
|
'type' => [
|
||||||
'name' => 'String',
|
'name' => 'String',
|
||||||
'kind' => 'SCALAR',
|
'kind' => 'SCALAR',
|
||||||
'ofType' => null
|
'ofType' => null,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
@ -329,7 +336,7 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
}
|
}
|
||||||
';
|
';
|
||||||
|
|
||||||
$expected = array(
|
$expected = [
|
||||||
'__schema' => [
|
'__schema' => [
|
||||||
'queryType' => [
|
'queryType' => [
|
||||||
'fields' => [
|
'fields' => [
|
||||||
@ -337,13 +344,13 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
'name' => 'hero',
|
'name' => 'hero',
|
||||||
'args' => [
|
'args' => [
|
||||||
[
|
[
|
||||||
'defaultValue' => NULL,
|
'defaultValue' => null,
|
||||||
'description' => 'If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.',
|
'description' => 'If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.',
|
||||||
'name' => 'episode',
|
'name' => 'episode',
|
||||||
'type' => [
|
'type' => [
|
||||||
'kind' => 'ENUM',
|
'kind' => 'ENUM',
|
||||||
'name' => 'Episode',
|
'name' => 'Episode',
|
||||||
'ofType' => NULL,
|
'ofType' => null,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@ -356,13 +363,13 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
'description' => 'id of the human',
|
'description' => 'id of the human',
|
||||||
'type' => [
|
'type' => [
|
||||||
'kind' => 'NON_NULL',
|
'kind' => 'NON_NULL',
|
||||||
'name' => NULL,
|
'name' => null,
|
||||||
'ofType' => [
|
'ofType' => [
|
||||||
'kind' => 'SCALAR',
|
'kind' => 'SCALAR',
|
||||||
'name' => 'String',
|
'name' => 'String',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'defaultValue' => NULL,
|
'defaultValue' => null,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@ -374,21 +381,21 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
'description' => 'id of the droid',
|
'description' => 'id of the droid',
|
||||||
'type' => [
|
'type' => [
|
||||||
'kind' => 'NON_NULL',
|
'kind' => 'NON_NULL',
|
||||||
'name' => NULL,
|
'name' => null,
|
||||||
'ofType' =>
|
'ofType' =>
|
||||||
[
|
[
|
||||||
'kind' => 'SCALAR',
|
'kind' => 'SCALAR',
|
||||||
'name' => 'String',
|
'name' => 'String',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'defaultValue' => NULL,
|
'defaultValue' => null,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
);
|
];
|
||||||
|
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
@ -409,17 +416,9 @@ class StarWarsIntrospectionTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'__type' => [
|
'__type' => [
|
||||||
'name' => 'Droid',
|
'name' => 'Droid',
|
||||||
'description' => 'A mechanical creature in the Star Wars universe.'
|
'description' => 'A mechanical creature in the Star Wars universe.',
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to test a query and the expected response.
|
|
||||||
*/
|
|
||||||
private function assertValidQuery($query, $expected)
|
|
||||||
{
|
|
||||||
$this->assertEquals(['data' => $expected], GraphQL::executeQuery(StarWarsSchema::build(), $query)->toArray());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests;
|
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests;
|
||||||
|
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class StarWarsQueryTest extends TestCase
|
class StarWarsQueryTest extends TestCase
|
||||||
{
|
{
|
||||||
// Star Wars Query Tests
|
|
||||||
// Basic Queries
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Correctly identifies R2-D2 as the hero of the Star Wars Saga')
|
* @see it('Correctly identifies R2-D2 as the hero of the Star Wars Saga')
|
||||||
*/
|
*/
|
||||||
@ -23,13 +22,24 @@ class StarWarsQueryTest extends TestCase
|
|||||||
}
|
}
|
||||||
';
|
';
|
||||||
$expected = [
|
$expected = [
|
||||||
'hero' => [
|
'hero' => ['name' => 'R2-D2'],
|
||||||
'name' => 'R2-D2'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to test a query and the expected response.
|
||||||
|
*/
|
||||||
|
private function assertValidQuery($query, $expected) : void
|
||||||
|
{
|
||||||
|
$this->assertEquals(
|
||||||
|
['data' => $expected],
|
||||||
|
GraphQL::executeQuery(StarWarsSchema::build(), $query)->toArray()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe: Nested Queries
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Allows us to query for the ID and friends of R2-D2')
|
* @see it('Allows us to query for the ID and friends of R2-D2')
|
||||||
*/
|
*/
|
||||||
@ -51,22 +61,16 @@ class StarWarsQueryTest extends TestCase
|
|||||||
'id' => '2001',
|
'id' => '2001',
|
||||||
'name' => 'R2-D2',
|
'name' => 'R2-D2',
|
||||||
'friends' => [
|
'friends' => [
|
||||||
[
|
['name' => 'Luke Skywalker'],
|
||||||
'name' => 'Luke Skywalker',
|
['name' => 'Han Solo'],
|
||||||
|
['name' => 'Leia Organa'],
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'name' => 'Han Solo',
|
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'name' => 'Leia Organa',
|
|
||||||
],
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: Nested Queries
|
// Describe: Using IDs and query parameters to refetch objects
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Allows us to query for the friends of friends of R2-D2')
|
* @see it('Allows us to query for the friends of friends of R2-D2')
|
||||||
@ -93,42 +97,40 @@ class StarWarsQueryTest extends TestCase
|
|||||||
'friends' => [
|
'friends' => [
|
||||||
[
|
[
|
||||||
'name' => 'Luke Skywalker',
|
'name' => 'Luke Skywalker',
|
||||||
'appearsIn' => ['NEWHOPE', 'EMPIRE', 'JEDI',],
|
'appearsIn' => ['NEWHOPE', 'EMPIRE', 'JEDI'],
|
||||||
'friends' => [
|
'friends' => [
|
||||||
['name' => 'Han Solo',],
|
['name' => 'Han Solo'],
|
||||||
['name' => 'Leia Organa',],
|
['name' => 'Leia Organa'],
|
||||||
['name' => 'C-3PO',],
|
['name' => 'C-3PO'],
|
||||||
['name' => 'R2-D2',],
|
['name' => 'R2-D2'],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'Han Solo',
|
'name' => 'Han Solo',
|
||||||
'appearsIn' => ['NEWHOPE', 'EMPIRE', 'JEDI'],
|
'appearsIn' => ['NEWHOPE', 'EMPIRE', 'JEDI'],
|
||||||
'friends' => [
|
'friends' => [
|
||||||
['name' => 'Luke Skywalker',],
|
['name' => 'Luke Skywalker'],
|
||||||
['name' => 'Leia Organa'],
|
['name' => 'Leia Organa'],
|
||||||
['name' => 'R2-D2',],
|
['name' => 'R2-D2'],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'Leia Organa',
|
'name' => 'Leia Organa',
|
||||||
'appearsIn' => ['NEWHOPE', 'EMPIRE', 'JEDI'],
|
'appearsIn' => ['NEWHOPE', 'EMPIRE', 'JEDI'],
|
||||||
'friends' =>
|
'friends' =>
|
||||||
[
|
[
|
||||||
['name' => 'Luke Skywalker',],
|
['name' => 'Luke Skywalker'],
|
||||||
['name' => 'Han Solo',],
|
['name' => 'Han Solo'],
|
||||||
['name' => 'C-3PO',],
|
['name' => 'C-3PO'],
|
||||||
['name' => 'R2-D2',],
|
['name' => 'R2-D2'],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: Using IDs and query parameters to refetch objects
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Using IDs and query parameters to refetch objects')
|
* @see it('Using IDs and query parameters to refetch objects')
|
||||||
*/
|
*/
|
||||||
@ -142,9 +144,7 @@ class StarWarsQueryTest extends TestCase
|
|||||||
}
|
}
|
||||||
';
|
';
|
||||||
$expected = [
|
$expected = [
|
||||||
'human' => [
|
'human' => ['name' => 'Luke Skywalker'],
|
||||||
'name' => 'Luke Skywalker'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
@ -162,18 +162,27 @@ class StarWarsQueryTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
';
|
';
|
||||||
$params = [
|
$params = ['someId' => '1000'];
|
||||||
'someId' => '1000'
|
|
||||||
];
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'human' => [
|
'human' => ['name' => 'Luke Skywalker'],
|
||||||
'name' => 'Luke Skywalker'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertValidQueryWithParams($query, $params, $expected);
|
$this->assertValidQueryWithParams($query, $params, $expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to test a query with params and the expected response.
|
||||||
|
*/
|
||||||
|
private function assertValidQueryWithParams($query, $params, $expected)
|
||||||
|
{
|
||||||
|
$this->assertEquals(
|
||||||
|
['data' => $expected],
|
||||||
|
GraphQL::executeQuery(StarWarsSchema::build(), $query, null, null, $params)->toArray()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using aliases to change the key in the response
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Allows us to create a generic query, then use it to fetch Han Solo using his ID')
|
* @see it('Allows us to create a generic query, then use it to fetch Han Solo using his ID')
|
||||||
*/
|
*/
|
||||||
@ -186,13 +195,9 @@ class StarWarsQueryTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
';
|
';
|
||||||
$params = [
|
$params = ['someId' => '1002'];
|
||||||
'someId' => '1002'
|
|
||||||
];
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'human' => [
|
'human' => ['name' => 'Han Solo'],
|
||||||
'name' => 'Han Solo'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertValidQueryWithParams($query, $params, $expected);
|
$this->assertValidQueryWithParams($query, $params, $expected);
|
||||||
}
|
}
|
||||||
@ -209,21 +214,17 @@ class StarWarsQueryTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
';
|
';
|
||||||
$params = [
|
$params = ['id' => 'not a valid id'];
|
||||||
'id' => 'not a valid id'
|
$expected = ['human' => null];
|
||||||
];
|
|
||||||
$expected = [
|
|
||||||
'human' => null
|
|
||||||
];
|
|
||||||
$this->assertValidQueryWithParams($query, $params, $expected);
|
$this->assertValidQueryWithParams($query, $params, $expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using aliases to change the key in the response
|
// Uses fragments to express more complex queries
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Allows us to query for Luke, changing his key with an alias')
|
* @see it('Allows us to query for Luke, changing his key with an alias')
|
||||||
*/
|
*/
|
||||||
function testLukeKeyAlias()
|
public function testLukeKeyAlias() : void
|
||||||
{
|
{
|
||||||
$query = '
|
$query = '
|
||||||
query FetchLukeAliased {
|
query FetchLukeAliased {
|
||||||
@ -233,9 +234,7 @@ class StarWarsQueryTest extends TestCase
|
|||||||
}
|
}
|
||||||
';
|
';
|
||||||
$expected = [
|
$expected = [
|
||||||
'luke' => [
|
'luke' => ['name' => 'Luke Skywalker'],
|
||||||
'name' => 'Luke Skywalker'
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
@ -243,7 +242,7 @@ class StarWarsQueryTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @see it('Allows us to query for both Luke and Leia, using two root fields and an alias')
|
* @see it('Allows us to query for both Luke and Leia, using two root fields and an alias')
|
||||||
*/
|
*/
|
||||||
function testTwoRootKeysAsAnAlias()
|
public function testTwoRootKeysAsAnAlias() : void
|
||||||
{
|
{
|
||||||
$query = '
|
$query = '
|
||||||
query FetchLukeAndLeiaAliased {
|
query FetchLukeAndLeiaAliased {
|
||||||
@ -256,22 +255,16 @@ class StarWarsQueryTest extends TestCase
|
|||||||
}
|
}
|
||||||
';
|
';
|
||||||
$expected = [
|
$expected = [
|
||||||
'luke' => [
|
'luke' => ['name' => 'Luke Skywalker'],
|
||||||
'name' => 'Luke Skywalker'
|
'leia' => ['name' => 'Leia Organa'],
|
||||||
],
|
|
||||||
'leia' => [
|
|
||||||
'name' => 'Leia Organa'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses fragments to express more complex queries
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Allows us to query using duplicated content')
|
* @see it('Allows us to query using duplicated content')
|
||||||
*/
|
*/
|
||||||
function testQueryUsingDuplicatedContent()
|
public function testQueryUsingDuplicatedContent() : void
|
||||||
{
|
{
|
||||||
$query = '
|
$query = '
|
||||||
query DuplicateFields {
|
query DuplicateFields {
|
||||||
@ -288,12 +281,12 @@ class StarWarsQueryTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'luke' => [
|
'luke' => [
|
||||||
'name' => 'Luke Skywalker',
|
'name' => 'Luke Skywalker',
|
||||||
'homePlanet' => 'Tatooine'
|
'homePlanet' => 'Tatooine',
|
||||||
],
|
],
|
||||||
'leia' => [
|
'leia' => [
|
||||||
'name' => 'Leia Organa',
|
'name' => 'Leia Organa',
|
||||||
'homePlanet' => 'Alderaan'
|
'homePlanet' => 'Alderaan',
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
@ -301,7 +294,7 @@ class StarWarsQueryTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @see it('Allows us to use a fragment to avoid duplicating content')
|
* @see it('Allows us to use a fragment to avoid duplicating content')
|
||||||
*/
|
*/
|
||||||
function testUsingFragment()
|
public function testUsingFragment() : void
|
||||||
{
|
{
|
||||||
$query = '
|
$query = '
|
||||||
query UseFragment {
|
query UseFragment {
|
||||||
@ -322,12 +315,12 @@ class StarWarsQueryTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'luke' => [
|
'luke' => [
|
||||||
'name' => 'Luke Skywalker',
|
'name' => 'Luke Skywalker',
|
||||||
'homePlanet' => 'Tatooine'
|
'homePlanet' => 'Tatooine',
|
||||||
],
|
],
|
||||||
'leia' => [
|
'leia' => [
|
||||||
'name' => 'Leia Organa',
|
'name' => 'Leia Organa',
|
||||||
'homePlanet' => 'Alderaan'
|
'homePlanet' => 'Alderaan',
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
@ -348,7 +341,7 @@ class StarWarsQueryTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'hero' => [
|
'hero' => [
|
||||||
'__typename' => 'Droid',
|
'__typename' => 'Droid',
|
||||||
'name' => 'R2-D2'
|
'name' => 'R2-D2',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
@ -371,32 +364,10 @@ class StarWarsQueryTest extends TestCase
|
|||||||
$expected = [
|
$expected = [
|
||||||
'hero' => [
|
'hero' => [
|
||||||
'__typename' => 'Human',
|
'__typename' => 'Human',
|
||||||
'name' => 'Luke Skywalker'
|
'name' => 'Luke Skywalker',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertValidQuery($query, $expected);
|
$this->assertValidQuery($query, $expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to test a query and the expected response.
|
|
||||||
*/
|
|
||||||
private function assertValidQuery($query, $expected)
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
['data' => $expected],
|
|
||||||
GraphQL::executeQuery(StarWarsSchema::build(), $query)->toArray()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to test a query with params and the expected response.
|
|
||||||
*/
|
|
||||||
private function assertValidQueryWithParams($query, $params, $expected)
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
['data' => $expected],
|
|
||||||
GraphQL::executeQuery(StarWarsSchema::build(), $query, null, null, $params)->toArray()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests;
|
namespace GraphQL\Tests;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,13 +14,16 @@ namespace GraphQL\Tests;
|
|||||||
* NOTE: This may contain spoilers for the original Star
|
* NOTE: This may contain spoilers for the original Star
|
||||||
* Wars trilogy.
|
* Wars trilogy.
|
||||||
*/
|
*/
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\EnumType;
|
use GraphQL\Type\Definition\EnumType;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\NonNull;
|
use GraphQL\Type\Definition\NonNull;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\ResolveInfo;
|
use GraphQL\Type\Definition\ResolveInfo;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
|
use function array_intersect_key;
|
||||||
|
use function array_map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Using our shorthand to describe type systems, the type system for our
|
* Using our shorthand to describe type systems, the type system for our
|
||||||
@ -56,10 +62,9 @@ use GraphQL\Type\Definition\Type;
|
|||||||
*
|
*
|
||||||
* We begin by setting up our schema.
|
* We begin by setting up our schema.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class StarWarsSchema
|
class StarWarsSchema
|
||||||
{
|
{
|
||||||
public static function build()
|
public static function build() : Schema
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The original trilogy consists of three movies.
|
* The original trilogy consists of three movies.
|
||||||
@ -73,17 +78,17 @@ class StarWarsSchema
|
|||||||
'values' => [
|
'values' => [
|
||||||
'NEWHOPE' => [
|
'NEWHOPE' => [
|
||||||
'value' => 4,
|
'value' => 4,
|
||||||
'description' => 'Released in 1977.'
|
'description' => 'Released in 1977.',
|
||||||
],
|
],
|
||||||
'EMPIRE' => [
|
'EMPIRE' => [
|
||||||
'value' => 5,
|
'value' => 5,
|
||||||
'description' => 'Released in 1980.'
|
'description' => 'Released in 1980.',
|
||||||
],
|
],
|
||||||
'JEDI' => [
|
'JEDI' => [
|
||||||
'value' => 6,
|
'value' => 6,
|
||||||
'description' => 'Released in 1983.'
|
'description' => 'Released in 1983.',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$humanType = null;
|
$humanType = null;
|
||||||
@ -103,7 +108,7 @@ class StarWarsSchema
|
|||||||
$characterInterface = new InterfaceType([
|
$characterInterface = new InterfaceType([
|
||||||
'name' => 'Character',
|
'name' => 'Character',
|
||||||
'description' => 'A character in the Star Wars Trilogy',
|
'description' => 'A character in the Star Wars Trilogy',
|
||||||
'fields' => function() use (&$characterInterface, $episodeEnum) {
|
'fields' => function () use (&$characterInterface, $episodeEnum) {
|
||||||
return [
|
return [
|
||||||
'id' => [
|
'id' => [
|
||||||
'type' => Type::nonNull(Type::string()),
|
'type' => Type::nonNull(Type::string()),
|
||||||
@ -111,7 +116,7 @@ class StarWarsSchema
|
|||||||
],
|
],
|
||||||
'name' => [
|
'name' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'description' => 'The name of the character.'
|
'description' => 'The name of the character.',
|
||||||
],
|
],
|
||||||
'friends' => [
|
'friends' => [
|
||||||
'type' => Type::listOf($characterInterface),
|
'type' => Type::listOf($characterInterface),
|
||||||
@ -119,7 +124,7 @@ class StarWarsSchema
|
|||||||
],
|
],
|
||||||
'appearsIn' => [
|
'appearsIn' => [
|
||||||
'type' => Type::listOf($episodeEnum),
|
'type' => Type::listOf($episodeEnum),
|
||||||
'description' => 'Which movies they appear in.'
|
'description' => 'Which movies they appear in.',
|
||||||
],
|
],
|
||||||
'secretBackstory' => [
|
'secretBackstory' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
@ -164,7 +169,7 @@ class StarWarsSchema
|
|||||||
$fieldSelection['id'] = true;
|
$fieldSelection['id'] = true;
|
||||||
|
|
||||||
$friends = array_map(
|
$friends = array_map(
|
||||||
function($friend) use ($fieldSelection) {
|
function ($friend) use ($fieldSelection) {
|
||||||
return array_intersect_key($friend, $fieldSelection);
|
return array_intersect_key($friend, $fieldSelection);
|
||||||
},
|
},
|
||||||
StarWarsData::getFriends($human)
|
StarWarsData::getFriends($human)
|
||||||
@ -175,22 +180,22 @@ class StarWarsSchema
|
|||||||
],
|
],
|
||||||
'appearsIn' => [
|
'appearsIn' => [
|
||||||
'type' => Type::listOf($episodeEnum),
|
'type' => Type::listOf($episodeEnum),
|
||||||
'description' => 'Which movies they appear in.'
|
'description' => 'Which movies they appear in.',
|
||||||
],
|
],
|
||||||
'homePlanet' => [
|
'homePlanet' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'description' => 'The home planet of the human, or null if unknown.'
|
'description' => 'The home planet of the human, or null if unknown.',
|
||||||
],
|
],
|
||||||
'secretBackstory' => [
|
'secretBackstory' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'description' => 'Where are they from and how they came to be who they are.',
|
'description' => 'Where are they from and how they came to be who they are.',
|
||||||
'resolve' => function() {
|
'resolve' => function () {
|
||||||
// This is to demonstrate error reporting
|
// This is to demonstrate error reporting
|
||||||
throw new \Exception('secretBackstory is secret.');
|
throw new \Exception('secretBackstory is secret.');
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'interfaces' => [$characterInterface]
|
'interfaces' => [$characterInterface],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -216,7 +221,7 @@ class StarWarsSchema
|
|||||||
],
|
],
|
||||||
'name' => [
|
'name' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'description' => 'The name of the droid.'
|
'description' => 'The name of the droid.',
|
||||||
],
|
],
|
||||||
'friends' => [
|
'friends' => [
|
||||||
'type' => Type::listOf($characterInterface),
|
'type' => Type::listOf($characterInterface),
|
||||||
@ -227,22 +232,22 @@ class StarWarsSchema
|
|||||||
],
|
],
|
||||||
'appearsIn' => [
|
'appearsIn' => [
|
||||||
'type' => Type::listOf($episodeEnum),
|
'type' => Type::listOf($episodeEnum),
|
||||||
'description' => 'Which movies they appear in.'
|
'description' => 'Which movies they appear in.',
|
||||||
],
|
],
|
||||||
'secretBackstory' => [
|
'secretBackstory' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'description' => 'Construction date and the name of the designer.',
|
'description' => 'Construction date and the name of the designer.',
|
||||||
'resolve' => function() {
|
'resolve' => function () {
|
||||||
// This is to demonstrate error reporting
|
// This is to demonstrate error reporting
|
||||||
throw new \Exception('secretBackstory is secret.');
|
throw new \Exception('secretBackstory is secret.');
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'primaryFunction' => [
|
'primaryFunction' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'description' => 'The primary function of the droid.'
|
'description' => 'The primary function of the droid.',
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'interfaces' => [$characterInterface]
|
],
|
||||||
|
'interfaces' => [$characterInterface],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -267,11 +272,11 @@ class StarWarsSchema
|
|||||||
'args' => [
|
'args' => [
|
||||||
'episode' => [
|
'episode' => [
|
||||||
'description' => 'If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.',
|
'description' => 'If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.',
|
||||||
'type' => $episodeEnum
|
'type' => $episodeEnum,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'resolve' => function ($root, $args) {
|
'resolve' => function ($root, $args) {
|
||||||
return StarWarsData::getHero(isset($args['episode']) ? $args['episode'] : null);
|
return StarWarsData::getHero($args['episode'] ?? null);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'human' => [
|
'human' => [
|
||||||
@ -280,13 +285,14 @@ class StarWarsSchema
|
|||||||
'id' => [
|
'id' => [
|
||||||
'name' => 'id',
|
'name' => 'id',
|
||||||
'description' => 'id of the human',
|
'description' => 'id of the human',
|
||||||
'type' => Type::nonNull(Type::string())
|
'type' => Type::nonNull(Type::string()),
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'resolve' => function ($root, $args) {
|
'resolve' => function ($root, $args) {
|
||||||
$humans = StarWarsData::humans();
|
$humans = StarWarsData::humans();
|
||||||
return isset($humans[$args['id']]) ? $humans[$args['id']] : null;
|
|
||||||
}
|
return $humans[$args['id']] ?? null;
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'droid' => [
|
'droid' => [
|
||||||
'type' => $droidType,
|
'type' => $droidType,
|
||||||
@ -294,15 +300,16 @@ class StarWarsSchema
|
|||||||
'id' => [
|
'id' => [
|
||||||
'name' => 'id',
|
'name' => 'id',
|
||||||
'description' => 'id of the droid',
|
'description' => 'id of the droid',
|
||||||
'type' => Type::nonNull(Type::string())
|
'type' => Type::nonNull(Type::string()),
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'resolve' => function ($root, $args) {
|
'resolve' => function ($root, $args) {
|
||||||
$droids = StarWarsData::droids();
|
$droids = StarWarsData::droids();
|
||||||
return isset($droids[$args['id']]) ? $droids[$args['id']] : null;
|
|
||||||
}
|
return $droids[$args['id']] ?? null;
|
||||||
]
|
},
|
||||||
]
|
],
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return new Schema(['query' => $queryType]);
|
return new Schema(['query' => $queryType]);
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests;
|
namespace GraphQL\Tests;
|
||||||
|
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
@ -37,6 +40,16 @@ class StarWarsValidationTest extends TestCase
|
|||||||
$this->assertEquals(true, empty($errors));
|
$this->assertEquals(true, empty($errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to test a query and the expected response.
|
||||||
|
*/
|
||||||
|
private function validationErrors($query)
|
||||||
|
{
|
||||||
|
$ast = Parser::parse($query);
|
||||||
|
|
||||||
|
return DocumentValidator::validate(StarWarsSchema::build(), $ast);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Notes that non-existent fields are invalid')
|
* @see it('Notes that non-existent fields are invalid')
|
||||||
*/
|
*/
|
||||||
@ -142,13 +155,4 @@ class StarWarsValidationTest extends TestCase
|
|||||||
$errors = $this->validationErrors($query);
|
$errors = $this->validationErrors($query);
|
||||||
$this->assertEquals(true, empty($errors));
|
$this->assertEquals(true, empty($errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to test a query and the expected response.
|
|
||||||
*/
|
|
||||||
private function validationErrors($query)
|
|
||||||
{
|
|
||||||
$ast = Parser::parse($query);
|
|
||||||
return DocumentValidator::validate(StarWarsSchema::build(), $ast);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Type;
|
namespace GraphQL\Tests\Type;
|
||||||
|
|
||||||
require_once __DIR__ . '/TestClasses.php';
|
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
|
use GraphQL\Tests\Type\TestClasses\MyCustomType;
|
||||||
|
use GraphQL\Tests\Type\TestClasses\OtherCustom;
|
||||||
use GraphQL\Type\Definition\CustomScalarType;
|
use GraphQL\Type\Definition\CustomScalarType;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\EnumType;
|
use GraphQL\Type\Definition\EnumType;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
@ -14,74 +16,53 @@ use GraphQL\Type\Definition\NonNull;
|
|||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\UnionType;
|
use GraphQL\Type\Definition\UnionType;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function count;
|
||||||
|
use function get_class;
|
||||||
|
use function json_encode;
|
||||||
|
use function sprintf;
|
||||||
|
|
||||||
class DefinitionTest extends TestCase
|
class DefinitionTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
public $blogImage;
|
public $blogImage;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
public $blogArticle;
|
public $blogArticle;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
public $blogAuthor;
|
public $blogAuthor;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
public $blogMutation;
|
public $blogMutation;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
public $blogQuery;
|
public $blogQuery;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
public $blogSubscription;
|
public $blogSubscription;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
public $objectType;
|
public $objectType;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
public $objectWithIsTypeOf;
|
public $objectWithIsTypeOf;
|
||||||
|
|
||||||
/**
|
/** @var InterfaceType */
|
||||||
* @var InterfaceType
|
|
||||||
*/
|
|
||||||
public $interfaceType;
|
public $interfaceType;
|
||||||
|
|
||||||
/**
|
/** @var UnionType */
|
||||||
* @var UnionType
|
|
||||||
*/
|
|
||||||
public $unionType;
|
public $unionType;
|
||||||
|
|
||||||
/**
|
/** @var EnumType */
|
||||||
* @var EnumType
|
|
||||||
*/
|
|
||||||
public $enumType;
|
public $enumType;
|
||||||
|
|
||||||
/**
|
/** @var InputObjectType */
|
||||||
* @var InputObjectType
|
|
||||||
*/
|
|
||||||
public $inputObjectType;
|
public $inputObjectType;
|
||||||
|
|
||||||
/**
|
/** @var CustomScalarType */
|
||||||
* @var CustomScalarType
|
|
||||||
*/
|
|
||||||
public $scalarType;
|
public $scalarType;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -99,9 +80,12 @@ class DefinitionTest extends TestCase
|
|||||||
|
|
||||||
$this->scalarType = new CustomScalarType([
|
$this->scalarType = new CustomScalarType([
|
||||||
'name' => 'Scalar',
|
'name' => 'Scalar',
|
||||||
'serialize' => function () {},
|
'serialize' => function () {
|
||||||
'parseValue' => function () {},
|
},
|
||||||
'parseLiteral' => function () {},
|
'parseValue' => function () {
|
||||||
|
},
|
||||||
|
'parseLiteral' => function () {
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->blogImage = new ObjectType([
|
$this->blogImage = new ObjectType([
|
||||||
@ -109,20 +93,23 @@ class DefinitionTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'url' => ['type' => Type::string()],
|
'url' => ['type' => Type::string()],
|
||||||
'width' => ['type' => Type::int()],
|
'width' => ['type' => Type::int()],
|
||||||
'height' => ['type' => Type::int()]
|
'height' => ['type' => Type::int()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->blogAuthor = new ObjectType([
|
$this->blogAuthor = new ObjectType([
|
||||||
'name' => 'Author',
|
'name' => 'Author',
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
'id' => ['type' => Type::string()],
|
'id' => ['type' => Type::string()],
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'pic' => [ 'type' => $this->blogImage, 'args' => [
|
'pic' => [
|
||||||
|
'type' => $this->blogImage,
|
||||||
|
'args' => [
|
||||||
'width' => ['type' => Type::int()],
|
'width' => ['type' => Type::int()],
|
||||||
'height' => ['type' => Type::int()]
|
'height' => ['type' => Type::int()],
|
||||||
]],
|
],
|
||||||
|
],
|
||||||
'recentArticle' => $this->blogArticle,
|
'recentArticle' => $this->blogArticle,
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
@ -135,35 +122,38 @@ class DefinitionTest extends TestCase
|
|||||||
'isPublished' => ['type' => Type::boolean()],
|
'isPublished' => ['type' => Type::boolean()],
|
||||||
'author' => ['type' => $this->blogAuthor],
|
'author' => ['type' => $this->blogAuthor],
|
||||||
'title' => ['type' => Type::string()],
|
'title' => ['type' => Type::string()],
|
||||||
'body' => ['type' => Type::string()]
|
'body' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->blogQuery = new ObjectType([
|
$this->blogQuery = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'article' => ['type' => $this->blogArticle, 'args' => [
|
'article' => [
|
||||||
'id' => ['type' => Type::string()]
|
'type' => $this->blogArticle,
|
||||||
]],
|
'args' => [
|
||||||
'feed' => ['type' => new ListOfType($this->blogArticle)]
|
'id' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
|
],
|
||||||
|
'feed' => ['type' => new ListOfType($this->blogArticle)],
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->blogMutation = new ObjectType([
|
$this->blogMutation = new ObjectType([
|
||||||
'name' => 'Mutation',
|
'name' => 'Mutation',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'writeArticle' => ['type' => $this->blogArticle]
|
'writeArticle' => ['type' => $this->blogArticle],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->blogSubscription = new ObjectType([
|
$this->blogSubscription = new ObjectType([
|
||||||
'name' => 'Subscription',
|
'name' => 'Subscription',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'articleSubscribe' => [
|
'articleSubscribe' => [
|
||||||
'args' => [ 'id' => [ 'type' => Type::string() ]],
|
'args' => ['id' => ['type' => Type::string()]],
|
||||||
'type' => $this->blogArticle
|
'type' => $this->blogArticle,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +165,7 @@ class DefinitionTest extends TestCase
|
|||||||
public function testDefinesAQueryOnlySchema() : void
|
public function testDefinesAQueryOnlySchema() : void
|
||||||
{
|
{
|
||||||
$blogSchema = new Schema([
|
$blogSchema = new Schema([
|
||||||
'query' => $this->blogQuery
|
'query' => $this->blogQuery,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertSame($blogSchema->getQueryType(), $this->blogQuery);
|
$this->assertSame($blogSchema->getQueryType(), $this->blogQuery);
|
||||||
@ -220,7 +210,7 @@ class DefinitionTest extends TestCase
|
|||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->blogQuery,
|
'query' => $this->blogQuery,
|
||||||
'mutation' => $this->blogMutation
|
'mutation' => $this->blogMutation,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertSame($this->blogMutation, $schema->getMutationType());
|
$this->assertSame($this->blogMutation, $schema->getMutationType());
|
||||||
@ -239,7 +229,7 @@ class DefinitionTest extends TestCase
|
|||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->blogQuery,
|
'query' => $this->blogQuery,
|
||||||
'subscription' => $this->blogSubscription
|
'subscription' => $this->blogSubscription,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals($this->blogSubscription, $schema->getSubscriptionType());
|
$this->assertEquals($this->blogSubscription, $schema->getSubscriptionType());
|
||||||
@ -258,19 +248,22 @@ class DefinitionTest extends TestCase
|
|||||||
$enumTypeWithDeprecatedValue = new EnumType([
|
$enumTypeWithDeprecatedValue = new EnumType([
|
||||||
'name' => 'EnumWithDeprecatedValue',
|
'name' => 'EnumWithDeprecatedValue',
|
||||||
'values' => [
|
'values' => [
|
||||||
'foo' => ['deprecationReason' => 'Just because']
|
'foo' => ['deprecationReason' => 'Just because'],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$value = $enumTypeWithDeprecatedValue->getValues()[0];
|
$value = $enumTypeWithDeprecatedValue->getValues()[0];
|
||||||
|
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'name' => 'foo',
|
'name' => 'foo',
|
||||||
'description' => null,
|
'description' => null,
|
||||||
'deprecationReason' => 'Just because',
|
'deprecationReason' => 'Just because',
|
||||||
'value' => 'foo',
|
'value' => 'foo',
|
||||||
'astNode' => null
|
'astNode' => null,
|
||||||
], (array) $value);
|
],
|
||||||
|
(array) $value
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertEquals(true, $value->isDeprecated());
|
$this->assertEquals(true, $value->isDeprecated());
|
||||||
}
|
}
|
||||||
@ -285,7 +278,7 @@ class DefinitionTest extends TestCase
|
|||||||
'values' => [
|
'values' => [
|
||||||
'NULL' => ['value' => null],
|
'NULL' => ['value' => null],
|
||||||
'UNDEFINED' => ['value' => null],
|
'UNDEFINED' => ['value' => null],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
@ -308,8 +301,8 @@ class DefinitionTest extends TestCase
|
|||||||
$actual = $EnumTypeWithNullishValue->getValues();
|
$actual = $EnumTypeWithNullishValue->getValues();
|
||||||
|
|
||||||
$this->assertEquals(count($expected), count($actual));
|
$this->assertEquals(count($expected), count($actual));
|
||||||
$this->assertArraySubset($expected[0], (array)$actual[0]);
|
$this->assertArraySubset($expected[0], (array) $actual[0]);
|
||||||
$this->assertArraySubset($expected[1], (array)$actual[1]);
|
$this->assertArraySubset($expected[1], (array) $actual[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -322,9 +315,9 @@ class DefinitionTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'bar' => [
|
'bar' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'deprecationReason' => 'A terrible reason'
|
'deprecationReason' => 'A terrible reason',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$field = $TypeWithDeprecatedField->getField('bar');
|
$field = $TypeWithDeprecatedField->getField('bar');
|
||||||
@ -343,25 +336,25 @@ class DefinitionTest extends TestCase
|
|||||||
{
|
{
|
||||||
$nestedInputObject = new InputObjectType([
|
$nestedInputObject = new InputObjectType([
|
||||||
'name' => 'NestedInputObject',
|
'name' => 'NestedInputObject',
|
||||||
'fields' => ['value' => ['type' => Type::string()]]
|
'fields' => ['value' => ['type' => Type::string()]],
|
||||||
]);
|
]);
|
||||||
$someInputObject = new InputObjectType([
|
$someInputObject = new InputObjectType([
|
||||||
'name' => 'SomeInputObject',
|
'name' => 'SomeInputObject',
|
||||||
'fields' => ['nested' => ['type' => $nestedInputObject]]
|
'fields' => ['nested' => ['type' => $nestedInputObject]],
|
||||||
]);
|
]);
|
||||||
$someMutation = new ObjectType([
|
$someMutation = new ObjectType([
|
||||||
'name' => 'SomeMutation',
|
'name' => 'SomeMutation',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'mutateSomething' => [
|
'mutateSomething' => [
|
||||||
'type' => $this->blogArticle,
|
'type' => $this->blogArticle,
|
||||||
'args' => ['input' => ['type' => $someInputObject]]
|
'args' => ['input' => ['type' => $someInputObject]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->blogQuery,
|
'query' => $this->blogQuery,
|
||||||
'mutation' => $someMutation
|
'mutation' => $someMutation,
|
||||||
]);
|
]);
|
||||||
$this->assertSame($nestedInputObject, $schema->getType('NestedInputObject'));
|
$this->assertSame($nestedInputObject, $schema->getType('NestedInputObject'));
|
||||||
}
|
}
|
||||||
@ -374,14 +367,14 @@ class DefinitionTest extends TestCase
|
|||||||
$someInterface = new InterfaceType([
|
$someInterface = new InterfaceType([
|
||||||
'name' => 'SomeInterface',
|
'name' => 'SomeInterface',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'f' => ['type' => Type::int()]
|
'f' => ['type' => Type::int()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$someSubtype = new ObjectType([
|
$someSubtype = new ObjectType([
|
||||||
'name' => 'SomeSubtype',
|
'name' => 'SomeSubtype',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'f' => ['type' => Type::int()]
|
'f' => ['type' => Type::int()],
|
||||||
],
|
],
|
||||||
'interfaces' => [$someInterface],
|
'interfaces' => [$someInterface],
|
||||||
]);
|
]);
|
||||||
@ -390,10 +383,10 @@ class DefinitionTest extends TestCase
|
|||||||
'query' => new ObjectType([
|
'query' => new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'iface' => ['type' => $someInterface]
|
'iface' => ['type' => $someInterface],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$someSubtype]
|
'types' => [$someSubtype],
|
||||||
]);
|
]);
|
||||||
$this->assertSame($someSubtype, $schema->getType('SomeSubtype'));
|
$this->assertSame($someSubtype, $schema->getType('SomeSubtype'));
|
||||||
}
|
}
|
||||||
@ -408,26 +401,28 @@ class DefinitionTest extends TestCase
|
|||||||
$someSubtype = new ObjectType([
|
$someSubtype = new ObjectType([
|
||||||
'name' => 'SomeSubtype',
|
'name' => 'SomeSubtype',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'f' => ['type' => Type::int()]
|
'f' => ['type' => Type::int()],
|
||||||
],
|
],
|
||||||
'interfaces' => function() use (&$someInterface) { return [$someInterface]; },
|
'interfaces' => function () use (&$someInterface) {
|
||||||
|
return [$someInterface];
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$someInterface = new InterfaceType([
|
$someInterface = new InterfaceType([
|
||||||
'name' => 'SomeInterface',
|
'name' => 'SomeInterface',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'f' => ['type' => Type::int()]
|
'f' => ['type' => Type::int()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => new ObjectType([
|
'query' => new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'iface' => ['type' => $someInterface]
|
'iface' => ['type' => $someInterface],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$someSubtype]
|
'types' => [$someSubtype],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertSame($someSubtype, $schema->getType('SomeSubtype'));
|
$this->assertSame($someSubtype, $schema->getType('SomeSubtype'));
|
||||||
@ -483,11 +478,15 @@ class DefinitionTest extends TestCase
|
|||||||
[$this->interfaceType, false],
|
[$this->interfaceType, false],
|
||||||
[$this->unionType, false],
|
[$this->unionType, false],
|
||||||
[$this->enumType, true],
|
[$this->enumType, true],
|
||||||
[$this->inputObjectType, true]
|
[$this->inputObjectType, true],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($expected as $index => $entry) {
|
foreach ($expected as $index => $entry) {
|
||||||
$this->assertSame($entry[1], Type::isInputType($entry[0]), "Type {$entry[0]} was detected incorrectly");
|
$this->assertSame(
|
||||||
|
$entry[1],
|
||||||
|
Type::isInputType($entry[0]),
|
||||||
|
sprintf('Type %s was detected incorrectly', $entry[0])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,11 +501,15 @@ class DefinitionTest extends TestCase
|
|||||||
[$this->interfaceType, true],
|
[$this->interfaceType, true],
|
||||||
[$this->unionType, true],
|
[$this->unionType, true],
|
||||||
[$this->enumType, true],
|
[$this->enumType, true],
|
||||||
[$this->inputObjectType, false]
|
[$this->inputObjectType, false],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($expected as $index => $entry) {
|
foreach ($expected as $index => $entry) {
|
||||||
$this->assertSame($entry[1], Type::isOutputType($entry[0]), "Type {$entry[0]} was detected incorrectly");
|
$this->assertSame(
|
||||||
|
$entry[1],
|
||||||
|
Type::isOutputType($entry[0]),
|
||||||
|
sprintf('Type %s was detected incorrectly', $entry[0])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,7 +532,9 @@ class DefinitionTest extends TestCase
|
|||||||
{
|
{
|
||||||
$union = new UnionType([
|
$union = new UnionType([
|
||||||
'name' => 'ThunkUnion',
|
'name' => 'ThunkUnion',
|
||||||
'types' => function() {return [$this->objectType]; }
|
'types' => function () {
|
||||||
|
return [$this->objectType];
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$types = $union->getTypes();
|
$types = $union->getTypes();
|
||||||
@ -543,8 +548,8 @@ class DefinitionTest extends TestCase
|
|||||||
$node = new InterfaceType([
|
$node = new InterfaceType([
|
||||||
'name' => 'Node',
|
'name' => 'Node',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'id' => ['type' => Type::nonNull(Type::id())]
|
'id' => ['type' => Type::nonNull(Type::id())],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$blog = null;
|
$blog = null;
|
||||||
@ -552,41 +557,41 @@ class DefinitionTest extends TestCase
|
|||||||
|
|
||||||
$user = new ObjectType([
|
$user = new ObjectType([
|
||||||
'name' => 'User',
|
'name' => 'User',
|
||||||
'fields' => function() use (&$blog, &$called) {
|
'fields' => function () use (&$blog, &$called) {
|
||||||
$this->assertNotNull($blog, 'Blog type is expected to be defined at this point, but it is null');
|
$this->assertNotNull($blog, 'Blog type is expected to be defined at this point, but it is null');
|
||||||
$called = true;
|
$called = true;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => ['type' => Type::nonNull(Type::id())],
|
'id' => ['type' => Type::nonNull(Type::id())],
|
||||||
'blogs' => ['type' => Type::nonNull(Type::listOf(Type::nonNull($blog)))]
|
'blogs' => ['type' => Type::nonNull(Type::listOf(Type::nonNull($blog)))],
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
'interfaces' => function() use ($node) {
|
'interfaces' => function () use ($node) {
|
||||||
return [$node];
|
return [$node];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$blog = new ObjectType([
|
$blog = new ObjectType([
|
||||||
'name' => 'Blog',
|
'name' => 'Blog',
|
||||||
'fields' => function() use ($user) {
|
'fields' => function () use ($user) {
|
||||||
return [
|
return [
|
||||||
'id' => ['type' => Type::nonNull(Type::id())],
|
'id' => ['type' => Type::nonNull(Type::id())],
|
||||||
'owner' => ['type' => Type::nonNull($user)]
|
'owner' => ['type' => Type::nonNull($user)],
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
'interfaces' => function() use ($node) {
|
'interfaces' => function () use ($node) {
|
||||||
return [$node];
|
return [$node];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => new ObjectType([
|
'query' => new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'node' => ['type' => $node]
|
'node' => ['type' => $node],
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'types' => [$user, $blog]
|
'types' => [$user, $blog],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertTrue($called);
|
$this->assertTrue($called);
|
||||||
@ -607,27 +612,29 @@ class DefinitionTest extends TestCase
|
|||||||
$called = false;
|
$called = false;
|
||||||
$inputObject = new InputObjectType([
|
$inputObject = new InputObjectType([
|
||||||
'name' => 'InputObject',
|
'name' => 'InputObject',
|
||||||
'fields' => function() use (&$inputObject, &$called) {
|
'fields' => function () use (&$inputObject, &$called) {
|
||||||
$called = true;
|
$called = true;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'value' => ['type' => Type::string()],
|
'value' => ['type' => Type::string()],
|
||||||
'nested' => ['type' => $inputObject ]
|
'nested' => ['type' => $inputObject],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$someMutation = new ObjectType([
|
$someMutation = new ObjectType([
|
||||||
'name' => 'SomeMutation',
|
'name' => 'SomeMutation',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'mutateSomething' => [
|
'mutateSomething' => [
|
||||||
'type' => $this->blogArticle,
|
'type' => $this->blogArticle,
|
||||||
'args' => ['input' => ['type' => $inputObject]]
|
'args' => ['input' => ['type' => $inputObject]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->blogQuery,
|
'query' => $this->blogQuery,
|
||||||
'mutation' => $someMutation
|
'mutation' => $someMutation,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertSame($inputObject, $schema->getType('InputObject'));
|
$this->assertSame($inputObject, $schema->getType('InputObject'));
|
||||||
@ -642,25 +649,24 @@ class DefinitionTest extends TestCase
|
|||||||
$called = false;
|
$called = false;
|
||||||
$interface = new InterfaceType([
|
$interface = new InterfaceType([
|
||||||
'name' => 'SomeInterface',
|
'name' => 'SomeInterface',
|
||||||
'fields' => function() use (&$interface, &$called) {
|
'fields' => function () use (&$interface, &$called) {
|
||||||
$called = true;
|
$called = true;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'value' => ['type' => Type::string()],
|
'value' => ['type' => Type::string()],
|
||||||
'nested' => ['type' => $interface ]
|
'nested' => ['type' => $interface],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'test' => ['type' => $interface]
|
'test' => ['type' => $interface],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema(['query' => $query]);
|
||||||
'query' => $query
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->assertSame($interface, $schema->getType('SomeInterface'));
|
$this->assertSame($interface, $schema->getType('SomeInterface'));
|
||||||
$this->assertTrue($called);
|
$this->assertTrue($called);
|
||||||
@ -673,30 +679,26 @@ class DefinitionTest extends TestCase
|
|||||||
{
|
{
|
||||||
$interface = new InterfaceType([
|
$interface = new InterfaceType([
|
||||||
'name' => 'SomeInterface',
|
'name' => 'SomeInterface',
|
||||||
'fields' => function() use (&$interface) {
|
'fields' => function () use (&$interface) {
|
||||||
return [
|
return [
|
||||||
'value' => Type::string(),
|
'value' => Type::string(),
|
||||||
'nested' => $interface,
|
'nested' => $interface,
|
||||||
'withArg' => [
|
'withArg' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'args' => [
|
'args' => [
|
||||||
'arg1' => Type::int()
|
'arg1' => Type::int(),
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => ['test' => $interface],
|
||||||
'test' => $interface
|
|
||||||
]
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema(['query' => $query]);
|
||||||
'query' => $query
|
|
||||||
]);
|
|
||||||
|
|
||||||
$valueField = $schema->getType('SomeInterface')->getField('value');
|
$valueField = $schema->getType('SomeInterface')->getField('value');
|
||||||
$nestedField = $schema->getType('SomeInterface')->getField('nested');
|
$nestedField = $schema->getType('SomeInterface')->getField('nested');
|
||||||
@ -728,14 +730,17 @@ class DefinitionTest extends TestCase
|
|||||||
{
|
{
|
||||||
$idType = new CustomScalarType([
|
$idType = new CustomScalarType([
|
||||||
'name' => 'ID',
|
'name' => 'ID',
|
||||||
'serialize' => function() {},
|
'serialize' => function () {
|
||||||
'parseValue' => function() {},
|
},
|
||||||
'parseLiteral' => function() {}
|
'parseValue' => function () {
|
||||||
|
},
|
||||||
|
'parseLiteral' => function () {
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => new ObjectType(['name' => 'Query', 'fields' => []]),
|
'query' => new ObjectType(['name' => 'Query', 'fields' => []]),
|
||||||
'types' => [$idType]
|
'types' => [$idType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertSame($idType, $schema->getType('ID'));
|
$this->assertSame($idType, $schema->getType('ID'));
|
||||||
@ -767,9 +772,7 @@ class DefinitionTest extends TestCase
|
|||||||
{
|
{
|
||||||
$objType = new ObjectType([
|
$objType = new ObjectType([
|
||||||
'name' => 'SomeObject',
|
'name' => 'SomeObject',
|
||||||
'fields' => [
|
'fields' => ['f' => null],
|
||||||
'f' => null,
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
$this->expectException(InvariantViolation::class);
|
$this->expectException(InvariantViolation::class);
|
||||||
$this->expectExceptionMessage(
|
$this->expectExceptionMessage(
|
||||||
@ -929,6 +932,17 @@ class DefinitionTest extends TestCase
|
|||||||
|
|
||||||
// Type System: Object fields must have valid resolve values
|
// Type System: Object fields must have valid resolve values
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see it('accepts a lambda as an Object field resolver')
|
||||||
|
*/
|
||||||
|
public function testAcceptsALambdaAsAnObjectFieldResolver() : void
|
||||||
|
{
|
||||||
|
$this->expectNotToPerformAssertions();
|
||||||
|
// should not throw:
|
||||||
|
$this->schemaWithObjectWithFieldResolver(function () {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private function schemaWithObjectWithFieldResolver($resolveValue)
|
private function schemaWithObjectWithFieldResolver($resolveValue)
|
||||||
{
|
{
|
||||||
$BadResolverType = new ObjectType([
|
$BadResolverType = new ObjectType([
|
||||||
@ -950,17 +964,8 @@ class DefinitionTest extends TestCase
|
|||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
$schema->assertValid();
|
$schema->assertValid();
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return $schema;
|
||||||
* @see it('accepts a lambda as an Object field resolver')
|
|
||||||
*/
|
|
||||||
public function testAcceptsALambdaAsAnObjectFieldResolver() : void
|
|
||||||
{
|
|
||||||
$this->expectNotToPerformAssertions();
|
|
||||||
// should not throw:
|
|
||||||
$this->schemaWithObjectWithFieldResolver(function () {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -987,21 +992,8 @@ class DefinitionTest extends TestCase
|
|||||||
$this->schemaWithObjectWithFieldResolver(0);
|
$this->schemaWithObjectWithFieldResolver(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Type System: Interface types must be resolvable
|
// Type System: Interface types must be resolvable
|
||||||
|
|
||||||
private function schemaWithFieldType($type)
|
|
||||||
{
|
|
||||||
$schema = new Schema([
|
|
||||||
'query' => new ObjectType([
|
|
||||||
'name' => 'Query',
|
|
||||||
'fields' => ['field' => ['type' => $type]],
|
|
||||||
]),
|
|
||||||
'types' => [$type],
|
|
||||||
]);
|
|
||||||
$schema->assertValid();
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts an Interface type defining resolveType')
|
* @see it('accepts an Interface type defining resolveType')
|
||||||
*/
|
*/
|
||||||
@ -1023,6 +1015,20 @@ class DefinitionTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function schemaWithFieldType($type)
|
||||||
|
{
|
||||||
|
$schema = new Schema([
|
||||||
|
'query' => new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => ['field' => ['type' => $type]],
|
||||||
|
]),
|
||||||
|
'types' => [$type],
|
||||||
|
]);
|
||||||
|
$schema->assertValid();
|
||||||
|
|
||||||
|
return $schema;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts an Interface with implementing type defining isTypeOf')
|
* @see it('accepts an Interface with implementing type defining isTypeOf')
|
||||||
*/
|
*/
|
||||||
@ -1085,14 +1091,6 @@ class DefinitionTest extends TestCase
|
|||||||
|
|
||||||
// Type System: Union types must be resolvable
|
// Type System: Union types must be resolvable
|
||||||
|
|
||||||
private function ObjectWithIsTypeOf()
|
|
||||||
{
|
|
||||||
return new ObjectType([
|
|
||||||
'name' => 'ObjectWithIsTypeOf',
|
|
||||||
'fields' => ['f' => ['type' => Type::string()]],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts a Union type defining resolveType')
|
* @see it('accepts a Union type defining resolveType')
|
||||||
*/
|
*/
|
||||||
@ -1156,8 +1154,6 @@ class DefinitionTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type System: Scalar types must be serializable
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts a Scalar type defining serialize')
|
* @see it('accepts a Scalar type defining serialize')
|
||||||
*/
|
*/
|
||||||
@ -1175,6 +1171,8 @@ class DefinitionTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type System: Scalar types must be serializable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('rejects a Scalar type not defining serialize')
|
* @see it('rejects a Scalar type not defining serialize')
|
||||||
*/
|
*/
|
||||||
@ -1187,9 +1185,7 @@ class DefinitionTest extends TestCase
|
|||||||
'functions are also provided.'
|
'functions are also provided.'
|
||||||
);
|
);
|
||||||
$this->schemaWithFieldType(
|
$this->schemaWithFieldType(
|
||||||
new CustomScalarType([
|
new CustomScalarType(['name' => 'SomeScalar'])
|
||||||
'name' => 'SomeScalar',
|
|
||||||
])
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1292,8 +1288,6 @@ class DefinitionTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type System: Object types must be assertable
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts an Object type with an isTypeOf function')
|
* @see it('accepts an Object type with an isTypeOf function')
|
||||||
*/
|
*/
|
||||||
@ -1309,6 +1303,8 @@ class DefinitionTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type System: Object types must be assertable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('rejects an Object type with an incorrect type for isTypeOf')
|
* @see it('rejects an Object type with an incorrect type for isTypeOf')
|
||||||
*/
|
*/
|
||||||
@ -1327,8 +1323,6 @@ class DefinitionTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type System: Union types must be array
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts a Union type with array types')
|
* @see it('accepts a Union type with array types')
|
||||||
*/
|
*/
|
||||||
@ -1344,6 +1338,8 @@ class DefinitionTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type System: Union types must be array
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts a Union type with function returning an array of types')
|
* @see it('accepts a Union type with function returning an array of types')
|
||||||
*/
|
*/
|
||||||
@ -1370,9 +1366,7 @@ class DefinitionTest extends TestCase
|
|||||||
'Must provide Array of types or a callable which returns such an array for Union SomeUnion'
|
'Must provide Array of types or a callable which returns such an array for Union SomeUnion'
|
||||||
);
|
);
|
||||||
$this->schemaWithFieldType(
|
$this->schemaWithFieldType(
|
||||||
new UnionType([
|
new UnionType(['name' => 'SomeUnion'])
|
||||||
'name' => 'SomeUnion',
|
|
||||||
])
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1388,13 +1382,11 @@ class DefinitionTest extends TestCase
|
|||||||
$this->schemaWithFieldType(
|
$this->schemaWithFieldType(
|
||||||
new UnionType([
|
new UnionType([
|
||||||
'name' => 'SomeUnion',
|
'name' => 'SomeUnion',
|
||||||
'types' => (object)[ 'test' => $this->objectType, ],
|
'types' => (object) ['test' => $this->objectType],
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type System: Input Objects must have fields
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts an Input Object type with fields')
|
* @see it('accepts an Input Object type with fields')
|
||||||
*/
|
*/
|
||||||
@ -1410,6 +1402,8 @@ class DefinitionTest extends TestCase
|
|||||||
$this->assertSame(Type::string(), $inputObjType->getField('f')->getType());
|
$this->assertSame(Type::string(), $inputObjType->getField('f')->getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type System: Input Objects must have fields
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts an Input Object type with a field function')
|
* @see it('accepts an Input Object type with a field function')
|
||||||
*/
|
*/
|
||||||
@ -1438,7 +1432,7 @@ class DefinitionTest extends TestCase
|
|||||||
]);
|
]);
|
||||||
$this->expectException(InvariantViolation::class);
|
$this->expectException(InvariantViolation::class);
|
||||||
$this->expectExceptionMessage(
|
$this->expectExceptionMessage(
|
||||||
'SomeInputObject fields must be an associative array with field names as keys or a callable '.
|
'SomeInputObject fields must be an associative array with field names as keys or a callable ' .
|
||||||
'which returns such an array.'
|
'which returns such an array.'
|
||||||
);
|
);
|
||||||
$inputObjType->assertValid();
|
$inputObjType->assertValid();
|
||||||
@ -1463,8 +1457,6 @@ class DefinitionTest extends TestCase
|
|||||||
$inputObjType->assertValid();
|
$inputObjType->assertValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type System: Input Object fields must not have resolvers
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('rejects an Input Object type with resolvers')
|
* @see it('rejects an Input Object type with resolvers')
|
||||||
*/
|
*/
|
||||||
@ -1489,6 +1481,8 @@ class DefinitionTest extends TestCase
|
|||||||
$inputObjType->assertValid();
|
$inputObjType->assertValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type System: Input Object fields must not have resolvers
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('rejects an Input Object type with resolver constant')
|
* @see it('rejects an Input Object type with resolver constant')
|
||||||
*/
|
*/
|
||||||
@ -1511,8 +1505,6 @@ class DefinitionTest extends TestCase
|
|||||||
$inputObjType->assertValid();
|
$inputObjType->assertValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type System: Enum types must be well defined
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts a well defined Enum type with empty value definition')
|
* @see it('accepts a well defined Enum type with empty value definition')
|
||||||
*/
|
*/
|
||||||
@ -1529,6 +1521,8 @@ class DefinitionTest extends TestCase
|
|||||||
$this->assertEquals('BAR', $enumType->getValue('BAR')->value);
|
$this->assertEquals('BAR', $enumType->getValue('BAR')->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type System: Enum types must be well defined
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('accepts a well defined Enum type with internal value definition')
|
* @see it('accepts a well defined Enum type with internal value definition')
|
||||||
*/
|
*/
|
||||||
@ -1569,9 +1563,7 @@ class DefinitionTest extends TestCase
|
|||||||
$enumType = new EnumType([
|
$enumType = new EnumType([
|
||||||
'name' => 'SomeEnum',
|
'name' => 'SomeEnum',
|
||||||
'values' => [
|
'values' => [
|
||||||
'FOO' => [
|
'FOO' => ['isDeprecated' => true],
|
||||||
'isDeprecated' => true,
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
$this->expectException(InvariantViolation::class);
|
$this->expectException(InvariantViolation::class);
|
||||||
@ -1582,7 +1574,6 @@ class DefinitionTest extends TestCase
|
|||||||
$enumType->assertValid();
|
$enumType->assertValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type System: List must accept only types
|
* Type System: List must accept only types
|
||||||
*/
|
*/
|
||||||
@ -1606,21 +1597,20 @@ class DefinitionTest extends TestCase
|
|||||||
try {
|
try {
|
||||||
Type::listOf($type);
|
Type::listOf($type);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->fail("List is expected to accept type: " . get_class($type) . ", but got error: ". $e->getMessage());
|
$this->fail('List is expected to accept type: ' . get_class($type) . ', but got error: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($badTypes as $badType) {
|
foreach ($badTypes as $badType) {
|
||||||
$typeStr = Utils::printSafe($badType);
|
$typeStr = Utils::printSafe($badType);
|
||||||
try {
|
try {
|
||||||
Type::listOf($badType);
|
Type::listOf($badType);
|
||||||
$this->fail("List should not accept $typeStr");
|
$this->fail(sprintf('List should not accept %s', $typeStr));
|
||||||
} catch (InvariantViolation $e) {
|
} catch (InvariantViolation $e) {
|
||||||
$this->assertEquals("Expected $typeStr to be a GraphQL type.", $e->getMessage());
|
$this->assertEquals(sprintf('Expected %s to be a GraphQL type.', $typeStr), $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type System: NonNull must only accept non-nullable types
|
* Type System: NonNull must only accept non-nullable types
|
||||||
*/
|
*/
|
||||||
@ -1648,22 +1638,20 @@ class DefinitionTest extends TestCase
|
|||||||
try {
|
try {
|
||||||
Type::nonNull($type);
|
Type::nonNull($type);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->fail("NonNull is expected to accept type: " . get_class($type) . ", but got error: ". $e->getMessage());
|
$this->fail('NonNull is expected to accept type: ' . get_class($type) . ', but got error: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($notNullableTypes as $badType) {
|
foreach ($notNullableTypes as $badType) {
|
||||||
$typeStr = Utils::printSafe($badType);
|
$typeStr = Utils::printSafe($badType);
|
||||||
try {
|
try {
|
||||||
Type::nonNull($badType);
|
Type::nonNull($badType);
|
||||||
$this->fail("Nulls should not accept $typeStr");
|
$this->fail(sprintf('Nulls should not accept %s', $typeStr));
|
||||||
} catch (InvariantViolation $e) {
|
} catch (InvariantViolation $e) {
|
||||||
$this->assertEquals("Expected $typeStr to be a GraphQL nullable type.", $e->getMessage());
|
$this->assertEquals(sprintf('Expected %s to be a GraphQL nullable type.', $typeStr), $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type System: A Schema must contain uniquely named types
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('rejects a Schema which redefines a built-in type')
|
* @see it('rejects a Schema which redefines a built-in type')
|
||||||
*/
|
*/
|
||||||
@ -1685,13 +1673,15 @@ class DefinitionTest extends TestCase
|
|||||||
|
|
||||||
$this->expectException(InvariantViolation::class);
|
$this->expectException(InvariantViolation::class);
|
||||||
$this->expectExceptionMessage(
|
$this->expectExceptionMessage(
|
||||||
'Schema must contain unique named types but contains multiple types named "String" '.
|
'Schema must contain unique named types but contains multiple types named "String" ' .
|
||||||
'(see http://webonyx.github.io/graphql-php/type-system/#type-registry).'
|
'(see http://webonyx.github.io/graphql-php/type-system/#type-registry).'
|
||||||
);
|
);
|
||||||
$schema = new Schema(['query' => $QueryType]);
|
$schema = new Schema(['query' => $QueryType]);
|
||||||
$schema->assertValid();
|
$schema->assertValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type System: A Schema must contain uniquely named types
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('rejects a Schema which defines an object type twice')
|
* @see it('rejects a Schema which defines an object type twice')
|
||||||
*/
|
*/
|
||||||
@ -1719,7 +1709,7 @@ class DefinitionTest extends TestCase
|
|||||||
'Schema must contain unique named types but contains multiple types named "SameName" ' .
|
'Schema must contain unique named types but contains multiple types named "SameName" ' .
|
||||||
'(see http://webonyx.github.io/graphql-php/type-system/#type-registry).'
|
'(see http://webonyx.github.io/graphql-php/type-system/#type-registry).'
|
||||||
);
|
);
|
||||||
$schema = new Schema([ 'query' => $QueryType ]);
|
$schema = new Schema(['query' => $QueryType]);
|
||||||
$schema->assertValid();
|
$schema->assertValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1763,4 +1753,12 @@ class DefinitionTest extends TestCase
|
|||||||
]);
|
]);
|
||||||
$schema->assertValid();
|
$schema->assertValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function objectWithIsTypeOf() : ObjectType
|
||||||
|
{
|
||||||
|
return new ObjectType([
|
||||||
|
'name' => 'ObjectWithIsTypeOf',
|
||||||
|
'fields' => ['f' => ['type' => Type::string()]],
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,33 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Type;
|
namespace GraphQL\Tests\Type;
|
||||||
|
|
||||||
|
use ArrayObject;
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Language\SourceLocation;
|
use GraphQL\Language\SourceLocation;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\EnumType;
|
use GraphQL\Type\Definition\EnumType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Introspection;
|
use GraphQL\Type\Introspection;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function count;
|
||||||
|
use function is_array;
|
||||||
|
|
||||||
class EnumTypeTest extends TestCase
|
class EnumTypeTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var Schema */
|
||||||
* @var Schema
|
|
||||||
*/
|
|
||||||
private $schema;
|
private $schema;
|
||||||
|
|
||||||
/**
|
/** @var EnumType */
|
||||||
* @var EnumType
|
|
||||||
*/
|
|
||||||
private $ComplexEnum;
|
private $ComplexEnum;
|
||||||
|
|
||||||
|
/** @var mixed[] */
|
||||||
private $Complex1;
|
private $Complex1;
|
||||||
|
|
||||||
|
/** @var ArrayObject */
|
||||||
private $Complex2;
|
private $Complex2;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -34,25 +38,30 @@ class EnumTypeTest extends TestCase
|
|||||||
'RED' => ['value' => 0],
|
'RED' => ['value' => 0],
|
||||||
'GREEN' => ['value' => 1],
|
'GREEN' => ['value' => 1],
|
||||||
'BLUE' => ['value' => 2],
|
'BLUE' => ['value' => 2],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$simpleEnum = new EnumType([
|
$simpleEnum = new EnumType([
|
||||||
'name' => 'SimpleEnum',
|
'name' => 'SimpleEnum',
|
||||||
'values' => [
|
'values' => [
|
||||||
'ONE', 'TWO', 'THREE'
|
'ONE',
|
||||||
]
|
'TWO',
|
||||||
|
'THREE',
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$Complex1 = ['someRandomFunction' => function() {}];
|
$Complex1 = [
|
||||||
|
'someRandomFunction' => function () {
|
||||||
|
},
|
||||||
|
];
|
||||||
$Complex2 = new \ArrayObject(['someRandomValue' => 123]);
|
$Complex2 = new \ArrayObject(['someRandomValue' => 123]);
|
||||||
|
|
||||||
$ComplexEnum = new EnumType([
|
$ComplexEnum = new EnumType([
|
||||||
'name' => 'Complex',
|
'name' => 'Complex',
|
||||||
'values' => [
|
'values' => [
|
||||||
'ONE' => ['value' => $Complex1],
|
'ONE' => ['value' => $Complex1],
|
||||||
'TWO' => ['value' => $Complex2]
|
'TWO' => ['value' => $Complex2],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$QueryType = new ObjectType([
|
$QueryType = new ObjectType([
|
||||||
@ -75,22 +84,22 @@ class EnumTypeTest extends TestCase
|
|||||||
if (isset($args['fromEnum'])) {
|
if (isset($args['fromEnum'])) {
|
||||||
return $args['fromEnum'];
|
return $args['fromEnum'];
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'simpleEnum' => [
|
'simpleEnum' => [
|
||||||
'type' => $simpleEnum,
|
'type' => $simpleEnum,
|
||||||
'args' => [
|
'args' => [
|
||||||
'fromName' => ['type' => Type::string()],
|
'fromName' => ['type' => Type::string()],
|
||||||
'fromValue' => ['type' => Type::string()]
|
'fromValue' => ['type' => Type::string()],
|
||||||
],
|
],
|
||||||
'resolve' => function($value, $args) {
|
'resolve' => function ($value, $args) {
|
||||||
if (isset($args['fromName'])) {
|
if (isset($args['fromName'])) {
|
||||||
return $args['fromName'];
|
return $args['fromName'];
|
||||||
}
|
}
|
||||||
if (isset($args['fromValue'])) {
|
if (isset($args['fromValue'])) {
|
||||||
return $args['fromValue'];
|
return $args['fromValue'];
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'colorInt' => [
|
'colorInt' => [
|
||||||
'type' => Type::int(),
|
'type' => Type::int(),
|
||||||
@ -105,7 +114,7 @@ class EnumTypeTest extends TestCase
|
|||||||
if (isset($args['fromEnum'])) {
|
if (isset($args['fromEnum'])) {
|
||||||
return $args['fromEnum'];
|
return $args['fromEnum'];
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
'complexEnum' => [
|
'complexEnum' => [
|
||||||
'type' => $ComplexEnum,
|
'type' => $ComplexEnum,
|
||||||
@ -114,30 +123,31 @@ class EnumTypeTest extends TestCase
|
|||||||
'type' => $ComplexEnum,
|
'type' => $ComplexEnum,
|
||||||
// Note: defaultValue is provided an *internal* representation for
|
// Note: defaultValue is provided an *internal* representation for
|
||||||
// Enums, rather than the string name.
|
// Enums, rather than the string name.
|
||||||
'defaultValue' => $Complex1
|
'defaultValue' => $Complex1,
|
||||||
],
|
],
|
||||||
'provideGoodValue' => [
|
'provideGoodValue' => [
|
||||||
'type' => Type::boolean(),
|
'type' => Type::boolean(),
|
||||||
],
|
],
|
||||||
'provideBadValue' => [
|
'provideBadValue' => [
|
||||||
'type' => Type::boolean()
|
'type' => Type::boolean(),
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'resolve' => function($value, $args) use ($Complex1, $Complex2) {
|
],
|
||||||
if (!empty($args['provideGoodValue'])) {
|
'resolve' => function ($value, $args) use ($Complex2) {
|
||||||
|
if (! empty($args['provideGoodValue'])) {
|
||||||
// Note: this is one of the references of the internal values which
|
// Note: this is one of the references of the internal values which
|
||||||
// ComplexEnum allows.
|
// ComplexEnum allows.
|
||||||
return $Complex2;
|
return $Complex2;
|
||||||
}
|
}
|
||||||
if (!empty($args['provideBadValue'])) {
|
if (! empty($args['provideBadValue'])) {
|
||||||
// Note: similar shape, but not the same *reference*
|
// Note: similar shape, but not the same *reference*
|
||||||
// as Complex2 above. Enum internal values require === equality.
|
// as Complex2 above. Enum internal values require === equality.
|
||||||
return new \ArrayObject(['someRandomValue' => 123]);
|
return new \ArrayObject(['someRandomValue' => 123]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $args['fromEnum'];
|
return $args['fromEnum'];
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$MutationType = new ObjectType([
|
$MutationType = new ObjectType([
|
||||||
@ -147,10 +157,10 @@ class EnumTypeTest extends TestCase
|
|||||||
'type' => $ColorType,
|
'type' => $ColorType,
|
||||||
'args' => ['color' => ['type' => $ColorType]],
|
'args' => ['color' => ['type' => $ColorType]],
|
||||||
'resolve' => function ($value, $args) {
|
'resolve' => function ($value, $args) {
|
||||||
return isset($args['color']) ? $args['color'] : null;
|
return $args['color'] ?? null;
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$SubscriptionType = new ObjectType([
|
$SubscriptionType = new ObjectType([
|
||||||
@ -160,10 +170,10 @@ class EnumTypeTest extends TestCase
|
|||||||
'type' => $ColorType,
|
'type' => $ColorType,
|
||||||
'args' => ['color' => ['type' => $ColorType]],
|
'args' => ['color' => ['type' => $ColorType]],
|
||||||
'resolve' => function ($value, $args) {
|
'resolve' => function ($value, $args) {
|
||||||
return isset($args['color']) ? $args['color'] : null;
|
return $args['color'] ?? null;
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->Complex1 = $Complex1;
|
$this->Complex1 = $Complex1;
|
||||||
@ -173,7 +183,7 @@ class EnumTypeTest extends TestCase
|
|||||||
$this->schema = new Schema([
|
$this->schema = new Schema([
|
||||||
'query' => $QueryType,
|
'query' => $QueryType,
|
||||||
'mutation' => $MutationType,
|
'mutation' => $MutationType,
|
||||||
'subscription' => $SubscriptionType
|
'subscription' => $SubscriptionType,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,12 +231,34 @@ class EnumTypeTest extends TestCase
|
|||||||
'{ colorEnum(fromEnum: "GREEN") }',
|
'{ colorEnum(fromEnum: "GREEN") }',
|
||||||
null,
|
null,
|
||||||
[
|
[
|
||||||
'message' => "Expected type Color, found \"GREEN\"; Did you mean the enum value GREEN?",
|
'message' => 'Expected type Color, found "GREEN"; Did you mean the enum value GREEN?',
|
||||||
'locations' => [new SourceLocation(1, 23)]
|
'locations' => [new SourceLocation(1, 23)],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function expectFailure($query, $vars, $err)
|
||||||
|
{
|
||||||
|
$result = GraphQL::executeQuery($this->schema, $query, null, null, $vars);
|
||||||
|
$this->assertEquals(1, count($result->errors));
|
||||||
|
|
||||||
|
if (is_array($err)) {
|
||||||
|
$this->assertEquals(
|
||||||
|
$err['message'],
|
||||||
|
$result->errors[0]->getMessage()
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
$err['locations'],
|
||||||
|
$result->errors[0]->getLocations()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->assertEquals(
|
||||||
|
$err,
|
||||||
|
$result->errors[0]->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('does not accept valuesNotInTheEnum')
|
* @see it('does not accept valuesNotInTheEnum')
|
||||||
*/
|
*/
|
||||||
@ -236,8 +268,8 @@ class EnumTypeTest extends TestCase
|
|||||||
'{ colorEnum(fromEnum: GREENISH) }',
|
'{ colorEnum(fromEnum: GREENISH) }',
|
||||||
null,
|
null,
|
||||||
[
|
[
|
||||||
'message' => "Expected type Color, found GREENISH; Did you mean the enum value GREEN?",
|
'message' => 'Expected type Color, found GREENISH; Did you mean the enum value GREEN?',
|
||||||
'locations' => [new SourceLocation(1, 23)]
|
'locations' => [new SourceLocation(1, 23)],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -251,8 +283,8 @@ class EnumTypeTest extends TestCase
|
|||||||
'{ colorEnum(fromEnum: green) }',
|
'{ colorEnum(fromEnum: green) }',
|
||||||
null,
|
null,
|
||||||
[
|
[
|
||||||
'message' => "Expected type Color, found green; Did you mean the enum value GREEN?",
|
'message' => 'Expected type Color, found green; Did you mean the enum value GREEN?',
|
||||||
'locations' => [new SourceLocation(1, 23)]
|
'locations' => [new SourceLocation(1, 23)],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -281,7 +313,7 @@ class EnumTypeTest extends TestCase
|
|||||||
$this->expectFailure(
|
$this->expectFailure(
|
||||||
'{ colorEnum(fromEnum: 1) }',
|
'{ colorEnum(fromEnum: 1) }',
|
||||||
null,
|
null,
|
||||||
"Expected type Color, found 1."
|
'Expected type Color, found 1.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +325,7 @@ class EnumTypeTest extends TestCase
|
|||||||
$this->expectFailure(
|
$this->expectFailure(
|
||||||
'{ colorEnum(fromInt: GREEN) }',
|
'{ colorEnum(fromInt: GREEN) }',
|
||||||
null,
|
null,
|
||||||
"Expected type Int, found GREEN."
|
'Expected type Int, found GREEN.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +413,7 @@ class EnumTypeTest extends TestCase
|
|||||||
$this->expectFailure(
|
$this->expectFailure(
|
||||||
'query test($color: Int!) { colorEnum(fromEnum: $color) }',
|
'query test($color: Int!) { colorEnum(fromEnum: $color) }',
|
||||||
['color' => 2],
|
['color' => 2],
|
||||||
'Variable "$color" of type "Int!" used in position ' . 'expecting type "Color".'
|
'Variable "$color" of type "Int!" used in position expecting type "Color".'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,10 +424,13 @@ class EnumTypeTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
['data' => ['colorEnum' => 'RED', 'colorInt' => 0]],
|
['data' => ['colorEnum' => 'RED', 'colorInt' => 0]],
|
||||||
GraphQL::executeQuery($this->schema, "{
|
GraphQL::executeQuery(
|
||||||
|
$this->schema,
|
||||||
|
'{
|
||||||
colorEnum(fromEnum: RED)
|
colorEnum(fromEnum: RED)
|
||||||
colorInt(fromEnum: RED)
|
colorInt(fromEnum: RED)
|
||||||
}")->toArray()
|
}'
|
||||||
|
)->toArray()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,10 +441,13 @@ class EnumTypeTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
['data' => ['colorEnum' => null, 'colorInt' => null]],
|
['data' => ['colorEnum' => null, 'colorInt' => null]],
|
||||||
GraphQL::executeQuery($this->schema, "{
|
GraphQL::executeQuery(
|
||||||
|
$this->schema,
|
||||||
|
'{
|
||||||
colorEnum
|
colorEnum
|
||||||
colorInt
|
colorInt
|
||||||
}")->toArray()
|
}'
|
||||||
|
)->toArray()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,25 +484,29 @@ class EnumTypeTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testMayBeInternallyRepresentedWithComplexValues() : void
|
public function testMayBeInternallyRepresentedWithComplexValues() : void
|
||||||
{
|
{
|
||||||
$result = GraphQL::executeQuery($this->schema, '{
|
$result = GraphQL::executeQuery(
|
||||||
|
$this->schema,
|
||||||
|
'{
|
||||||
first: complexEnum
|
first: complexEnum
|
||||||
second: complexEnum(fromEnum: TWO)
|
second: complexEnum(fromEnum: TWO)
|
||||||
good: complexEnum(provideGoodValue: true)
|
good: complexEnum(provideGoodValue: true)
|
||||||
bad: complexEnum(provideBadValue: true)
|
bad: complexEnum(provideBadValue: true)
|
||||||
}')->toArray(true);
|
}'
|
||||||
|
)->toArray(true);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'first' => 'ONE',
|
'first' => 'ONE',
|
||||||
'second' => 'TWO',
|
'second' => 'TWO',
|
||||||
'good' => 'TWO',
|
'good' => 'TWO',
|
||||||
'bad' => null
|
'bad' => null,
|
||||||
],
|
],
|
||||||
'errors' => [[
|
'errors' => [[
|
||||||
'debugMessage' =>
|
'debugMessage' =>
|
||||||
'Expected a value of type "Complex" but received: instance of ArrayObject',
|
'Expected a value of type "Complex" but received: instance of ArrayObject',
|
||||||
'locations' => [['line' => 5, 'column' => 9]]
|
'locations' => [['line' => 5, 'column' => 9]],
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertArraySubset($expected, $result);
|
$this->assertArraySubset($expected, $result);
|
||||||
@ -492,32 +534,11 @@ class EnumTypeTest extends TestCase
|
|||||||
'data' => ['first' => 'ONE', 'second' => 'TWO', 'third' => null],
|
'data' => ['first' => 'ONE', 'second' => 'TWO', 'third' => null],
|
||||||
'errors' => [[
|
'errors' => [[
|
||||||
'debugMessage' => 'Expected a value of type "SimpleEnum" but received: WRONG',
|
'debugMessage' => 'Expected a value of type "SimpleEnum" but received: WRONG',
|
||||||
'locations' => [['line' => 4, 'column' => 13]]
|
'locations' => [['line' => 4, 'column' => 13]],
|
||||||
]]
|
],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
GraphQL::executeQuery($this->schema, $q)->toArray(true)
|
GraphQL::executeQuery($this->schema, $q)->toArray(true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function expectFailure($query, $vars, $err)
|
|
||||||
{
|
|
||||||
$result = GraphQL::executeQuery($this->schema, $query, null, null, $vars);
|
|
||||||
$this->assertEquals(1, count($result->errors));
|
|
||||||
|
|
||||||
if (is_array($err)) {
|
|
||||||
$this->assertEquals(
|
|
||||||
$err['message'],
|
|
||||||
$result->errors[0]->getMessage()
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
$err['locations'],
|
|
||||||
$result->errors[0]->getLocations()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$this->assertEquals(
|
|
||||||
$err,
|
|
||||||
$result->errors[0]->getMessage()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Type;
|
namespace GraphQL\Tests\Type;
|
||||||
|
|
||||||
class ObjectIdStub
|
class ObjectIdStub
|
||||||
{
|
{
|
||||||
/**
|
/** @var int */
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
private $id;
|
private $id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Type;
|
namespace GraphQL\Tests\Type;
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
@ -10,75 +13,53 @@ use GraphQL\Type\Definition\UnionType;
|
|||||||
use GraphQL\Type\EagerResolution;
|
use GraphQL\Type\EagerResolution;
|
||||||
use GraphQL\Type\LazyResolution;
|
use GraphQL\Type\LazyResolution;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function lcfirst;
|
||||||
|
|
||||||
class ResolutionTest extends TestCase
|
class ResolutionTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $query;
|
private $query;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $mutation;
|
private $mutation;
|
||||||
|
|
||||||
/**
|
/** @var InterfaceType */
|
||||||
* @var InterfaceType
|
|
||||||
*/
|
|
||||||
private $node;
|
private $node;
|
||||||
|
|
||||||
/**
|
/** @var InterfaceType */
|
||||||
* @var InterfaceType
|
|
||||||
*/
|
|
||||||
private $content;
|
private $content;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $blogStory;
|
private $blogStory;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $link;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $video;
|
private $video;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $videoMetadata;
|
private $videoMetadata;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $comment;
|
private $comment;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $user;
|
private $user;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $category;
|
private $category;
|
||||||
|
|
||||||
/**
|
/** @var UnionType */
|
||||||
* @var UnionType
|
|
||||||
*/
|
|
||||||
private $mention;
|
private $mention;
|
||||||
|
|
||||||
|
/** @var ObjectType */
|
||||||
private $postStoryMutation;
|
private $postStoryMutation;
|
||||||
|
|
||||||
|
/** @var InputObjectType */
|
||||||
private $postStoryMutationInput;
|
private $postStoryMutationInput;
|
||||||
|
|
||||||
|
/** @var ObjectType */
|
||||||
private $postCommentMutation;
|
private $postCommentMutation;
|
||||||
|
|
||||||
|
/** @var InputObjectType */
|
||||||
private $postCommentMutationInput;
|
private $postCommentMutationInput;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -86,48 +67,30 @@ class ResolutionTest extends TestCase
|
|||||||
$this->node = new InterfaceType([
|
$this->node = new InterfaceType([
|
||||||
'name' => 'Node',
|
'name' => 'Node',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'id' => Type::string()
|
'id' => Type::string(),
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->content = new InterfaceType([
|
$this->content = new InterfaceType([
|
||||||
'name' => 'Content',
|
'name' => 'Content',
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
'title' => Type::string(),
|
'title' => Type::string(),
|
||||||
'body' => Type::string(),
|
'body' => Type::string(),
|
||||||
'author' => $this->user,
|
'author' => $this->user,
|
||||||
'comments' => Type::listOf($this->comment),
|
'comments' => Type::listOf($this->comment),
|
||||||
'categories' => Type::listOf($this->category)
|
'categories' => Type::listOf($this->category),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->blogStory = new ObjectType([
|
$this->blogStory = new ObjectType([
|
||||||
'name' => 'BlogStory',
|
'name' => 'BlogStory',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node,
|
$this->node,
|
||||||
$this->content
|
$this->content,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
|
||||||
$this->node->getField('id'),
|
|
||||||
$this->content->getField('title'),
|
|
||||||
$this->content->getField('body'),
|
|
||||||
$this->content->getField('author'),
|
|
||||||
$this->content->getField('comments'),
|
|
||||||
$this->content->getField('categories')
|
|
||||||
];
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->link = new ObjectType([
|
|
||||||
'name' => 'Link',
|
|
||||||
'interfaces' => [
|
|
||||||
$this->node,
|
|
||||||
$this->content
|
|
||||||
],
|
|
||||||
'fields' => function() {
|
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
$this->node->getField('id'),
|
||||||
$this->content->getField('title'),
|
$this->content->getField('title'),
|
||||||
@ -135,87 +98,108 @@ class ResolutionTest extends TestCase
|
|||||||
$this->content->getField('author'),
|
$this->content->getField('author'),
|
||||||
$this->content->getField('comments'),
|
$this->content->getField('comments'),
|
||||||
$this->content->getField('categories'),
|
$this->content->getField('categories'),
|
||||||
'url' => Type::string()
|
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
new ObjectType([
|
||||||
|
'name' => 'Link',
|
||||||
|
'interfaces' => [
|
||||||
|
$this->node,
|
||||||
|
$this->content,
|
||||||
|
],
|
||||||
|
'fields' => function () {
|
||||||
|
return [
|
||||||
|
'id' => $this->node->getField('id'),
|
||||||
|
'title' => $this->content->getField('title'),
|
||||||
|
'body' => $this->content->getField('body'),
|
||||||
|
'author' => $this->content->getField('author'),
|
||||||
|
'comments' => $this->content->getField('comments'),
|
||||||
|
'categories' => $this->content->getField('categories'),
|
||||||
|
'url' => Type::string(),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->videoMetadata = new ObjectType([
|
||||||
|
'name' => 'VideoMetadata',
|
||||||
|
'fields' => [
|
||||||
|
'lat' => Type::float(),
|
||||||
|
'lng' => Type::float(),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
$this->video = new ObjectType([
|
$this->video = new ObjectType([
|
||||||
'name' => 'Video',
|
'name' => 'Video',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node,
|
$this->node,
|
||||||
$this->content
|
$this->content,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
'id' => $this->node->getField('id'),
|
||||||
$this->content->getField('title'),
|
'title' => $this->content->getField('title'),
|
||||||
$this->content->getField('body'),
|
'body' => $this->content->getField('body'),
|
||||||
$this->content->getField('author'),
|
'author' => $this->content->getField('author'),
|
||||||
$this->content->getField('comments'),
|
'comments' => $this->content->getField('comments'),
|
||||||
$this->content->getField('categories'),
|
'categories' => $this->content->getField('categories'),
|
||||||
'streamUrl' => Type::string(),
|
'streamUrl' => Type::string(),
|
||||||
'downloadUrl' => Type::string(),
|
'downloadUrl' => Type::string(),
|
||||||
'metadata' => $this->videoMetadata = new ObjectType([
|
'metadata' => $this->videoMetadata,
|
||||||
'name' => 'VideoMetadata',
|
|
||||||
'fields' => [
|
|
||||||
'lat' => Type::float(),
|
|
||||||
'lng' => Type::float()
|
|
||||||
]
|
|
||||||
])
|
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->comment = new ObjectType([
|
$this->comment = new ObjectType([
|
||||||
'name' => 'Comment',
|
'name' => 'Comment',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node
|
$this->node,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
'id' => $this->node->getField('id'),
|
||||||
'author' => $this->user,
|
'author' => $this->user,
|
||||||
'text' => Type::string(),
|
'text' => Type::string(),
|
||||||
'replies' => Type::listOf($this->comment),
|
'replies' => Type::listOf($this->comment),
|
||||||
'parent' => $this->comment,
|
'parent' => $this->comment,
|
||||||
'content' => $this->content
|
'content' => $this->content,
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->user = new ObjectType([
|
$this->user = new ObjectType([
|
||||||
'name' => 'User',
|
'name' => 'User',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node
|
$this->node,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
'id' => $this->node->getField('id'),
|
||||||
'name' => Type::string(),
|
'name' => Type::string(),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->category = new ObjectType([
|
$this->category = new ObjectType([
|
||||||
'name' => 'Category',
|
'name' => 'Category',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node
|
$this->node,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
'id' => $this->node->getField('id'),
|
||||||
'name' => Type::string()
|
'name' => Type::string(),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->mention = new UnionType([
|
$this->mention = new UnionType([
|
||||||
'name' => 'Mention',
|
'name' => 'Mention',
|
||||||
'types' => [
|
'types' => [
|
||||||
$this->user,
|
$this->user,
|
||||||
$this->category
|
$this->category,
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->query = new ObjectType([
|
$this->query = new ObjectType([
|
||||||
@ -224,8 +208,18 @@ class ResolutionTest extends TestCase
|
|||||||
'viewer' => $this->user,
|
'viewer' => $this->user,
|
||||||
'latestContent' => $this->content,
|
'latestContent' => $this->content,
|
||||||
'node' => $this->node,
|
'node' => $this->node,
|
||||||
'mentions' => Type::listOf($this->mention)
|
'mentions' => Type::listOf($this->mention),
|
||||||
]
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->postStoryMutationInput = new InputObjectType([
|
||||||
|
'name' => 'PostStoryMutationInput',
|
||||||
|
'fields' => [
|
||||||
|
'title' => Type::string(),
|
||||||
|
'body' => Type::string(),
|
||||||
|
'author' => Type::id(),
|
||||||
|
'category' => Type::id(),
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->mutation = new ObjectType([
|
$this->mutation = new ObjectType([
|
||||||
@ -235,28 +229,20 @@ class ResolutionTest extends TestCase
|
|||||||
'type' => $this->postStoryMutation = new ObjectType([
|
'type' => $this->postStoryMutation = new ObjectType([
|
||||||
'name' => 'PostStoryMutation',
|
'name' => 'PostStoryMutation',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'story' => $this->blogStory
|
'story' => $this->blogStory,
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'args' => [
|
'args' => [
|
||||||
'input' => Type::nonNull($this->postStoryMutationInput = new InputObjectType([
|
'input' => Type::nonNull($this->postStoryMutationInput),
|
||||||
'name' => 'PostStoryMutationInput',
|
'clientRequestId' => Type::string(),
|
||||||
'fields' => [
|
],
|
||||||
'title' => Type::string(),
|
|
||||||
'body' => Type::string(),
|
|
||||||
'author' => Type::id(),
|
|
||||||
'category' => Type::id()
|
|
||||||
]
|
|
||||||
])),
|
|
||||||
'clientRequestId' => Type::string()
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'postComment' => [
|
'postComment' => [
|
||||||
'type' => $this->postCommentMutation = new ObjectType([
|
'type' => $this->postCommentMutation = new ObjectType([
|
||||||
'name' => 'PostCommentMutation',
|
'name' => 'PostCommentMutation',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'comment' => $this->comment
|
'comment' => $this->comment,
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'args' => [
|
'args' => [
|
||||||
'input' => Type::nonNull($this->postCommentMutationInput = new InputObjectType([
|
'input' => Type::nonNull($this->postCommentMutationInput = new InputObjectType([
|
||||||
@ -265,13 +251,13 @@ class ResolutionTest extends TestCase
|
|||||||
'text' => Type::nonNull(Type::string()),
|
'text' => Type::nonNull(Type::string()),
|
||||||
'author' => Type::nonNull(Type::id()),
|
'author' => Type::nonNull(Type::id()),
|
||||||
'content' => Type::id(),
|
'content' => Type::id(),
|
||||||
'parent' => Type::id()
|
'parent' => Type::id(),
|
||||||
]
|
],
|
||||||
])),
|
])),
|
||||||
'clientRequestId' => Type::string()
|
'clientRequestId' => Type::string(),
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +270,7 @@ class ResolutionTest extends TestCase
|
|||||||
'String' => Type::string(),
|
'String' => Type::string(),
|
||||||
'Float' => Type::float(),
|
'Float' => Type::float(),
|
||||||
'Int' => Type::int(),
|
'Int' => Type::int(),
|
||||||
'Boolean' => Type::boolean()
|
'Boolean' => Type::boolean(),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expectedTypeMap, $eagerTypeResolution->getTypeMap());
|
$this->assertEquals($expectedTypeMap, $eagerTypeResolution->getTypeMap());
|
||||||
|
|
||||||
@ -297,11 +283,11 @@ class ResolutionTest extends TestCase
|
|||||||
'Int' => 1,
|
'Int' => 1,
|
||||||
'Boolean' => 1,
|
'Boolean' => 1,
|
||||||
],
|
],
|
||||||
'possibleTypeMap' => []
|
'possibleTypeMap' => [],
|
||||||
];
|
];
|
||||||
$this->assertEquals($expectedDescriptor, $eagerTypeResolution->getDescriptor());
|
$this->assertEquals($expectedDescriptor, $eagerTypeResolution->getDescriptor());
|
||||||
|
|
||||||
$this->assertSame(null, $eagerTypeResolution->resolveType('User'));
|
$this->assertNull($eagerTypeResolution->resolveType('User'));
|
||||||
$this->assertSame([], $eagerTypeResolution->resolvePossibleTypes($this->node));
|
$this->assertSame([], $eagerTypeResolution->resolvePossibleTypes($this->node));
|
||||||
$this->assertSame([], $eagerTypeResolution->resolvePossibleTypes($this->content));
|
$this->assertSame([], $eagerTypeResolution->resolvePossibleTypes($this->content));
|
||||||
$this->assertSame([], $eagerTypeResolution->resolvePossibleTypes($this->mention));
|
$this->assertSame([], $eagerTypeResolution->resolvePossibleTypes($this->mention));
|
||||||
@ -321,10 +307,16 @@ class ResolutionTest extends TestCase
|
|||||||
$this->assertSame($this->postStoryMutation, $eagerTypeResolution->resolveType('PostStoryMutation'));
|
$this->assertSame($this->postStoryMutation, $eagerTypeResolution->resolveType('PostStoryMutation'));
|
||||||
$this->assertSame($this->postStoryMutationInput, $eagerTypeResolution->resolveType('PostStoryMutationInput'));
|
$this->assertSame($this->postStoryMutationInput, $eagerTypeResolution->resolveType('PostStoryMutationInput'));
|
||||||
$this->assertSame($this->postCommentMutation, $eagerTypeResolution->resolveType('PostCommentMutation'));
|
$this->assertSame($this->postCommentMutation, $eagerTypeResolution->resolveType('PostCommentMutation'));
|
||||||
$this->assertSame($this->postCommentMutationInput, $eagerTypeResolution->resolveType('PostCommentMutationInput'));
|
$this->assertSame(
|
||||||
|
$this->postCommentMutationInput,
|
||||||
|
$eagerTypeResolution->resolveType('PostCommentMutationInput')
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertEquals([$this->blogStory], $eagerTypeResolution->resolvePossibleTypes($this->content));
|
$this->assertEquals([$this->blogStory], $eagerTypeResolution->resolvePossibleTypes($this->content));
|
||||||
$this->assertEquals([$this->user, $this->comment, $this->category, $this->blogStory], $eagerTypeResolution->resolvePossibleTypes($this->node));
|
$this->assertEquals(
|
||||||
|
[$this->user, $this->comment, $this->category, $this->blogStory],
|
||||||
|
$eagerTypeResolution->resolvePossibleTypes($this->node)
|
||||||
|
);
|
||||||
$this->assertEquals([$this->user, $this->category], $eagerTypeResolution->resolvePossibleTypes($this->mention));
|
$this->assertEquals([$this->user, $this->category], $eagerTypeResolution->resolvePossibleTypes($this->mention));
|
||||||
|
|
||||||
$expectedTypeMap = [
|
$expectedTypeMap = [
|
||||||
@ -345,7 +337,7 @@ class ResolutionTest extends TestCase
|
|||||||
'PostCommentMutation' => $this->postCommentMutation,
|
'PostCommentMutation' => $this->postCommentMutation,
|
||||||
'Float' => Type::float(),
|
'Float' => Type::float(),
|
||||||
'Int' => Type::int(),
|
'Int' => Type::int(),
|
||||||
'Boolean' => Type::boolean()
|
'Boolean' => Type::boolean(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expectedTypeMap, $eagerTypeResolution->getTypeMap());
|
$this->assertEquals($expectedTypeMap, $eagerTypeResolution->getTypeMap());
|
||||||
@ -370,23 +362,21 @@ class ResolutionTest extends TestCase
|
|||||||
'PostCommentMutation' => 1,
|
'PostCommentMutation' => 1,
|
||||||
'Float' => 1,
|
'Float' => 1,
|
||||||
'Int' => 1,
|
'Int' => 1,
|
||||||
'Boolean' => 1
|
'Boolean' => 1,
|
||||||
],
|
],
|
||||||
'possibleTypeMap' => [
|
'possibleTypeMap' => [
|
||||||
'Node' => [
|
'Node' => [
|
||||||
'User' => 1,
|
'User' => 1,
|
||||||
'Comment' => 1,
|
'Comment' => 1,
|
||||||
'Category' => 1,
|
'Category' => 1,
|
||||||
'BlogStory' => 1
|
'BlogStory' => 1,
|
||||||
],
|
|
||||||
'Content' => [
|
|
||||||
'BlogStory' => 1
|
|
||||||
],
|
],
|
||||||
|
'Content' => ['BlogStory' => 1],
|
||||||
'Mention' => [
|
'Mention' => [
|
||||||
'User' => 1,
|
'User' => 1,
|
||||||
'Category' => 1
|
'Category' => 1,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expectedDescriptor, $eagerTypeResolution->getDescriptor());
|
$this->assertEquals($expectedDescriptor, $eagerTypeResolution->getDescriptor());
|
||||||
@ -402,7 +392,10 @@ class ResolutionTest extends TestCase
|
|||||||
$this->assertEquals(null, $eagerTypeResolution->resolveType('VideoMetadata'));
|
$this->assertEquals(null, $eagerTypeResolution->resolveType('VideoMetadata'));
|
||||||
|
|
||||||
$this->assertEquals([$this->blogStory], $eagerTypeResolution->resolvePossibleTypes($this->content));
|
$this->assertEquals([$this->blogStory], $eagerTypeResolution->resolvePossibleTypes($this->content));
|
||||||
$this->assertEquals([$this->user, $this->comment, $this->category, $this->blogStory], $eagerTypeResolution->resolvePossibleTypes($this->node));
|
$this->assertEquals(
|
||||||
|
[$this->user, $this->comment, $this->category, $this->blogStory],
|
||||||
|
$eagerTypeResolution->resolvePossibleTypes($this->node)
|
||||||
|
);
|
||||||
$this->assertEquals([$this->user, $this->category], $eagerTypeResolution->resolvePossibleTypes($this->mention));
|
$this->assertEquals([$this->user, $this->category], $eagerTypeResolution->resolvePossibleTypes($this->mention));
|
||||||
|
|
||||||
$eagerTypeResolution = new EagerResolution([null, $this->video, null]);
|
$eagerTypeResolution = new EagerResolution([null, $this->video, null]);
|
||||||
@ -410,7 +403,10 @@ class ResolutionTest extends TestCase
|
|||||||
$this->assertEquals($this->video, $eagerTypeResolution->resolveType('Video'));
|
$this->assertEquals($this->video, $eagerTypeResolution->resolveType('Video'));
|
||||||
|
|
||||||
$this->assertEquals([$this->video], $eagerTypeResolution->resolvePossibleTypes($this->content));
|
$this->assertEquals([$this->video], $eagerTypeResolution->resolvePossibleTypes($this->content));
|
||||||
$this->assertEquals([$this->video, $this->user, $this->comment, $this->category], $eagerTypeResolution->resolvePossibleTypes($this->node));
|
$this->assertEquals(
|
||||||
|
[$this->video, $this->user, $this->comment, $this->category],
|
||||||
|
$eagerTypeResolution->resolvePossibleTypes($this->node)
|
||||||
|
);
|
||||||
$this->assertEquals([], $eagerTypeResolution->resolvePossibleTypes($this->mention));
|
$this->assertEquals([], $eagerTypeResolution->resolvePossibleTypes($this->mention));
|
||||||
|
|
||||||
$expectedTypeMap = [
|
$expectedTypeMap = [
|
||||||
@ -425,7 +421,7 @@ class ResolutionTest extends TestCase
|
|||||||
'Float' => Type::float(),
|
'Float' => Type::float(),
|
||||||
'ID' => Type::id(),
|
'ID' => Type::id(),
|
||||||
'Int' => Type::int(),
|
'Int' => Type::int(),
|
||||||
'Boolean' => Type::boolean()
|
'Boolean' => Type::boolean(),
|
||||||
];
|
];
|
||||||
$this->assertEquals($expectedTypeMap, $eagerTypeResolution->getTypeMap());
|
$this->assertEquals($expectedTypeMap, $eagerTypeResolution->getTypeMap());
|
||||||
|
|
||||||
@ -443,19 +439,17 @@ class ResolutionTest extends TestCase
|
|||||||
'Float' => 1,
|
'Float' => 1,
|
||||||
'ID' => 1,
|
'ID' => 1,
|
||||||
'Int' => 1,
|
'Int' => 1,
|
||||||
'Boolean' => 1
|
'Boolean' => 1,
|
||||||
],
|
],
|
||||||
'possibleTypeMap' => [
|
'possibleTypeMap' => [
|
||||||
'Node' => [
|
'Node' => [
|
||||||
'Video' => 1,
|
'Video' => 1,
|
||||||
'User' => 1,
|
'User' => 1,
|
||||||
'Comment' => 1,
|
'Comment' => 1,
|
||||||
'Category' => 1
|
'Category' => 1,
|
||||||
|
],
|
||||||
|
'Content' => ['Video' => 1],
|
||||||
],
|
],
|
||||||
'Content' => [
|
|
||||||
'Video' => 1
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
$this->assertEquals($expectedDescriptor, $eagerTypeResolution->getDescriptor());
|
$this->assertEquals($expectedDescriptor, $eagerTypeResolution->getDescriptor());
|
||||||
}
|
}
|
||||||
@ -466,8 +460,8 @@ class ResolutionTest extends TestCase
|
|||||||
$eager = new EagerResolution([]);
|
$eager = new EagerResolution([]);
|
||||||
$emptyDescriptor = $eager->getDescriptor();
|
$emptyDescriptor = $eager->getDescriptor();
|
||||||
|
|
||||||
$typeLoader = function($name) {
|
$typeLoader = function ($name) {
|
||||||
throw new \Exception("This should be never called for empty descriptor");
|
throw new \Exception('This should be never called for empty descriptor');
|
||||||
};
|
};
|
||||||
|
|
||||||
$lazy = new LazyResolution($emptyDescriptor, $typeLoader);
|
$lazy = new LazyResolution($emptyDescriptor, $typeLoader);
|
||||||
@ -480,9 +474,10 @@ class ResolutionTest extends TestCase
|
|||||||
|
|
||||||
$called = 0;
|
$called = 0;
|
||||||
$descriptor = $eager->getDescriptor();
|
$descriptor = $eager->getDescriptor();
|
||||||
$typeLoader = function($name) use (&$called) {
|
$typeLoader = function ($name) use (&$called) {
|
||||||
$called++;
|
$called++;
|
||||||
$prop = lcfirst($name);
|
$prop = lcfirst($name);
|
||||||
|
|
||||||
return $this->{$prop};
|
return $this->{$prop};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -507,7 +502,10 @@ class ResolutionTest extends TestCase
|
|||||||
$this->assertSame($eager->resolveType('PostStoryMutation'), $lazy->resolveType('PostStoryMutation'));
|
$this->assertSame($eager->resolveType('PostStoryMutation'), $lazy->resolveType('PostStoryMutation'));
|
||||||
$this->assertSame($eager->resolveType('PostStoryMutationInput'), $lazy->resolveType('PostStoryMutationInput'));
|
$this->assertSame($eager->resolveType('PostStoryMutationInput'), $lazy->resolveType('PostStoryMutationInput'));
|
||||||
$this->assertSame($eager->resolveType('PostCommentMutation'), $lazy->resolveType('PostCommentMutation'));
|
$this->assertSame($eager->resolveType('PostCommentMutation'), $lazy->resolveType('PostCommentMutation'));
|
||||||
$this->assertSame($eager->resolveType('PostCommentMutationInput'), $lazy->resolveType('PostCommentMutationInput'));
|
$this->assertSame(
|
||||||
|
$eager->resolveType('PostCommentMutationInput'),
|
||||||
|
$lazy->resolveType('PostCommentMutationInput')
|
||||||
|
);
|
||||||
$this->assertSame(13, $called);
|
$this->assertSame(13, $called);
|
||||||
|
|
||||||
$this->assertEquals($eager->resolvePossibleTypes($this->content), $lazy->resolvePossibleTypes($this->content));
|
$this->assertEquals($eager->resolvePossibleTypes($this->content), $lazy->resolvePossibleTypes($this->content));
|
||||||
@ -527,25 +525,29 @@ class ResolutionTest extends TestCase
|
|||||||
$this->assertEquals($eager->resolvePossibleTypes($this->mention), $lazy->resolvePossibleTypes($this->mention));
|
$this->assertEquals($eager->resolvePossibleTypes($this->mention), $lazy->resolvePossibleTypes($this->mention));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createLazy(){
|
public function testLazyThrowsOnInvalidLoadedType() : void
|
||||||
|
{
|
||||||
|
$lazy = $this->createLazy();
|
||||||
|
$this->expectException(InvariantViolation::class);
|
||||||
|
$this->expectExceptionMessage('Lazy Type Resolution Error: Expecting GraphQL Type instance, but got integer');
|
||||||
|
$lazy->resolveType('int');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createLazy()
|
||||||
|
{
|
||||||
$descriptor = [
|
$descriptor = [
|
||||||
'version' => '1.0',
|
'version' => '1.0',
|
||||||
'typeMap' => [
|
'typeMap' => [
|
||||||
'null' => 1,
|
'null' => 1,
|
||||||
'int' => 1
|
'int' => 1,
|
||||||
],
|
],
|
||||||
'possibleTypeMap' => [
|
'possibleTypeMap' => [
|
||||||
'a' => [
|
'a' => ['null' => 1],
|
||||||
'null' => 1,
|
'b' => ['int' => 1],
|
||||||
],
|
],
|
||||||
'b' => [
|
|
||||||
'int' => 1
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$invalidTypeLoader = function($name) {
|
$invalidTypeLoader = function ($name) {
|
||||||
switch ($name) {
|
switch ($name) {
|
||||||
case 'null':
|
case 'null':
|
||||||
return null;
|
return null;
|
||||||
@ -561,14 +563,6 @@ class ResolutionTest extends TestCase
|
|||||||
return $lazy;
|
return $lazy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLazyThrowsOnInvalidLoadedType() : void
|
|
||||||
{
|
|
||||||
$lazy = $this->createLazy();
|
|
||||||
$this->expectException(InvariantViolation::class);
|
|
||||||
$this->expectExceptionMessage('Lazy Type Resolution Error: Expecting GraphQL Type instance, but got integer');
|
|
||||||
$lazy->resolveType('int');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testLazyThrowsOnInvalidLoadedPossibleType() : void
|
public function testLazyThrowsOnInvalidLoadedPossibleType() : void
|
||||||
{
|
{
|
||||||
$tmp = new InterfaceType(['name' => 'a', 'fields' => []]);
|
$tmp = new InterfaceType(['name' => 'a', 'fields' => []]);
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Type;
|
namespace GraphQL\Tests\Type;
|
||||||
|
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\ResolveInfo;
|
use GraphQL\Type\Definition\ResolveInfo;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class ResolveInfoTest extends TestCase
|
class ResolveInfoTest extends TestCase
|
||||||
@ -17,22 +20,25 @@ class ResolveInfoTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'url' => ['type' => Type::string()],
|
'url' => ['type' => Type::string()],
|
||||||
'width' => ['type' => Type::int()],
|
'width' => ['type' => Type::int()],
|
||||||
'height' => ['type' => Type::int()]
|
'height' => ['type' => Type::int()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$article = null;
|
$article = null;
|
||||||
|
|
||||||
$author = new ObjectType([
|
$author = new ObjectType([
|
||||||
'name' => 'Author',
|
'name' => 'Author',
|
||||||
'fields' => function() use ($image, &$article) {
|
'fields' => function () use ($image, &$article) {
|
||||||
return [
|
return [
|
||||||
'id' => ['type' => Type::string()],
|
'id' => ['type' => Type::string()],
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'pic' => [ 'type' => $image, 'args' => [
|
'pic' => [
|
||||||
|
'type' => $image,
|
||||||
|
'args' => [
|
||||||
'width' => ['type' => Type::int()],
|
'width' => ['type' => Type::int()],
|
||||||
'height' => ['type' => Type::int()]
|
'height' => ['type' => Type::int()],
|
||||||
]],
|
],
|
||||||
|
],
|
||||||
'recentArticle' => ['type' => $article],
|
'recentArticle' => ['type' => $article],
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
@ -42,8 +48,8 @@ class ResolveInfoTest extends TestCase
|
|||||||
'name' => 'Reply',
|
'name' => 'Reply',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'author' => ['type' => $author],
|
'author' => ['type' => $author],
|
||||||
'body' => ['type' => Type::string()]
|
'body' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$article = new ObjectType([
|
$article = new ObjectType([
|
||||||
@ -55,8 +61,8 @@ class ResolveInfoTest extends TestCase
|
|||||||
'title' => ['type' => Type::string()],
|
'title' => ['type' => Type::string()],
|
||||||
'body' => ['type' => Type::string()],
|
'body' => ['type' => Type::string()],
|
||||||
'image' => ['type' => $image],
|
'image' => ['type' => $image],
|
||||||
'replies' => ['type' => Type::listOf($reply)]
|
'replies' => ['type' => Type::listOf($reply)],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$doc = '
|
$doc = '
|
||||||
@ -102,20 +108,20 @@ class ResolveInfoTest extends TestCase
|
|||||||
$expectedDefaultSelection = [
|
$expectedDefaultSelection = [
|
||||||
'author' => true,
|
'author' => true,
|
||||||
'image' => true,
|
'image' => true,
|
||||||
'replies' => true
|
'replies' => true,
|
||||||
];
|
];
|
||||||
$expectedDeepSelection = [
|
$expectedDeepSelection = [
|
||||||
'author' => [
|
'author' => [
|
||||||
'name' => true,
|
'name' => true,
|
||||||
'pic' => [
|
'pic' => [
|
||||||
'url' => true,
|
'url' => true,
|
||||||
'width' => true
|
'width' => true,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'image' => [
|
'image' => [
|
||||||
'width' => true,
|
'width' => true,
|
||||||
'height' => true,
|
'height' => true,
|
||||||
'url' => true
|
'url' => true,
|
||||||
],
|
],
|
||||||
'replies' => [
|
'replies' => [
|
||||||
'body' => true,
|
'body' => true,
|
||||||
@ -125,15 +131,15 @@ class ResolveInfoTest extends TestCase
|
|||||||
'pic' => [
|
'pic' => [
|
||||||
'url' => true,
|
'url' => true,
|
||||||
'width' => true,
|
'width' => true,
|
||||||
'height' => true
|
'height' => true,
|
||||||
],
|
],
|
||||||
'recentArticle' => [
|
'recentArticle' => [
|
||||||
'id' => true,
|
'id' => true,
|
||||||
'title' => true,
|
'title' => true,
|
||||||
'body' => true
|
'body' => true,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$hasCalled = false;
|
$hasCalled = false;
|
||||||
@ -145,14 +151,25 @@ class ResolveInfoTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'article' => [
|
'article' => [
|
||||||
'type' => $article,
|
'type' => $article,
|
||||||
'resolve' => function($value, $args, $context, ResolveInfo $info) use (&$hasCalled, &$actualDefaultSelection, &$actualDeepSelection) {
|
'resolve' => function (
|
||||||
|
$value,
|
||||||
|
$args,
|
||||||
|
$context,
|
||||||
|
ResolveInfo $info
|
||||||
|
) use (
|
||||||
|
&$hasCalled,
|
||||||
|
&
|
||||||
|
$actualDefaultSelection,
|
||||||
|
&$actualDeepSelection
|
||||||
|
) {
|
||||||
$hasCalled = true;
|
$hasCalled = true;
|
||||||
$actualDefaultSelection = $info->getFieldSelection();
|
$actualDefaultSelection = $info->getFieldSelection();
|
||||||
$actualDeepSelection = $info->getFieldSelection(5);
|
$actualDeepSelection = $info->getFieldSelection(5);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $blogQuery]);
|
$schema = new Schema(['query' => $blogQuery]);
|
||||||
@ -171,22 +188,25 @@ class ResolveInfoTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'url' => ['type' => Type::string()],
|
'url' => ['type' => Type::string()],
|
||||||
'width' => ['type' => Type::int()],
|
'width' => ['type' => Type::int()],
|
||||||
'height' => ['type' => Type::int()]
|
'height' => ['type' => Type::int()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$article = null;
|
$article = null;
|
||||||
|
|
||||||
$author = new ObjectType([
|
$author = new ObjectType([
|
||||||
'name' => 'Author',
|
'name' => 'Author',
|
||||||
'fields' => function() use ($image, &$article) {
|
'fields' => function () use ($image, &$article) {
|
||||||
return [
|
return [
|
||||||
'id' => ['type' => Type::string()],
|
'id' => ['type' => Type::string()],
|
||||||
'name' => ['type' => Type::string()],
|
'name' => ['type' => Type::string()],
|
||||||
'pic' => [ 'type' => $image, 'args' => [
|
'pic' => [
|
||||||
|
'type' => $image,
|
||||||
|
'args' => [
|
||||||
'width' => ['type' => Type::int()],
|
'width' => ['type' => Type::int()],
|
||||||
'height' => ['type' => Type::int()]
|
'height' => ['type' => Type::int()],
|
||||||
]],
|
],
|
||||||
|
],
|
||||||
'recentArticle' => ['type' => $article],
|
'recentArticle' => ['type' => $article],
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
@ -196,8 +216,8 @@ class ResolveInfoTest extends TestCase
|
|||||||
'name' => 'Reply',
|
'name' => 'Reply',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'author' => ['type' => $author],
|
'author' => ['type' => $author],
|
||||||
'body' => ['type' => Type::string()]
|
'body' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$article = new ObjectType([
|
$article = new ObjectType([
|
||||||
@ -209,8 +229,8 @@ class ResolveInfoTest extends TestCase
|
|||||||
'title' => ['type' => Type::string()],
|
'title' => ['type' => Type::string()],
|
||||||
'body' => ['type' => Type::string()],
|
'body' => ['type' => Type::string()],
|
||||||
'image' => ['type' => $image],
|
'image' => ['type' => $image],
|
||||||
'replies' => ['type' => Type::listOf($reply)]
|
'replies' => ['type' => Type::listOf($reply)],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$doc = '
|
$doc = '
|
||||||
@ -268,13 +288,13 @@ class ResolveInfoTest extends TestCase
|
|||||||
'name' => true,
|
'name' => true,
|
||||||
'pic' => [
|
'pic' => [
|
||||||
'url' => true,
|
'url' => true,
|
||||||
'width' => true
|
'width' => true,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'image' => [
|
'image' => [
|
||||||
'width' => true,
|
'width' => true,
|
||||||
'height' => true,
|
'height' => true,
|
||||||
'url' => true
|
'url' => true,
|
||||||
],
|
],
|
||||||
'replies' => [
|
'replies' => [
|
||||||
'body' => true, //this would be missing if not for the fix https://github.com/webonyx/graphql-php/pull/98
|
'body' => true, //this would be missing if not for the fix https://github.com/webonyx/graphql-php/pull/98
|
||||||
@ -284,15 +304,15 @@ class ResolveInfoTest extends TestCase
|
|||||||
'pic' => [
|
'pic' => [
|
||||||
'url' => true,
|
'url' => true,
|
||||||
'width' => true,
|
'width' => true,
|
||||||
'height' => true
|
'height' => true,
|
||||||
],
|
],
|
||||||
'recentArticle' => [
|
'recentArticle' => [
|
||||||
'id' => true,
|
'id' => true,
|
||||||
'title' => true,
|
'title' => true,
|
||||||
'body' => true
|
'body' => true,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$hasCalled = false;
|
$hasCalled = false;
|
||||||
@ -304,13 +324,23 @@ class ResolveInfoTest extends TestCase
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'article' => [
|
'article' => [
|
||||||
'type' => $article,
|
'type' => $article,
|
||||||
'resolve' => function($value, $args, $context, ResolveInfo $info) use (&$hasCalled, &$actualDeepSelection) {
|
'resolve' => function (
|
||||||
|
$value,
|
||||||
|
$args,
|
||||||
|
$context,
|
||||||
|
ResolveInfo $info
|
||||||
|
) use (
|
||||||
|
&$hasCalled,
|
||||||
|
&
|
||||||
|
$actualDeepSelection
|
||||||
|
) {
|
||||||
$hasCalled = true;
|
$hasCalled = true;
|
||||||
$actualDeepSelection = $info->getFieldSelection(5);
|
$actualDeepSelection = $info->getFieldSelection(5);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $blogQuery]);
|
$schema = new Schema(['query' => $blogQuery]);
|
||||||
@ -320,6 +350,4 @@ class ResolveInfoTest extends TestCase
|
|||||||
$this->assertEquals(['data' => ['article' => null]], $result);
|
$this->assertEquals(['data' => ['article' => null]], $result);
|
||||||
$this->assertEquals($expectedDeepSelection, $actualDeepSelection);
|
$this->assertEquals($expectedDeepSelection, $actualDeepSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Type;
|
namespace GraphQL\Tests\Type;
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
@ -8,7 +11,6 @@ use PHPUnit\Framework\TestCase;
|
|||||||
class ScalarSerializationTest extends TestCase
|
class ScalarSerializationTest extends TestCase
|
||||||
{
|
{
|
||||||
// Type System: Scalar coercion
|
// Type System: Scalar coercion
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('serializes output int')
|
* @see it('serializes output int')
|
||||||
*/
|
*/
|
||||||
@ -42,7 +44,6 @@ class ScalarSerializationTest extends TestCase
|
|||||||
$this->expectException(Error::class);
|
$this->expectException(Error::class);
|
||||||
$this->expectExceptionMessage('Int cannot represent non-integer value: 1.1');
|
$this->expectExceptionMessage('Int cannot represent non-integer value: 1.1');
|
||||||
$intType->serialize(1.1);
|
$intType->serialize(1.1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSerializesOutputIntCannotRepresentNegativeFloat() : void
|
public function testSerializesOutputIntCannotRepresentNegativeFloat() : void
|
||||||
@ -51,7 +52,6 @@ class ScalarSerializationTest extends TestCase
|
|||||||
$this->expectException(Error::class);
|
$this->expectException(Error::class);
|
||||||
$this->expectExceptionMessage('Int cannot represent non-integer value: -1.1');
|
$this->expectExceptionMessage('Int cannot represent non-integer value: -1.1');
|
||||||
$intType->serialize(-1.1);
|
$intType->serialize(-1.1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSerializesOutputIntCannotRepresentNumericString() : void
|
public function testSerializesOutputIntCannotRepresentNumericString() : void
|
||||||
@ -60,7 +60,6 @@ class ScalarSerializationTest extends TestCase
|
|||||||
$this->expectException(Error::class);
|
$this->expectException(Error::class);
|
||||||
$this->expectExceptionMessage('Int cannot represent non 32-bit signed integer value: Int cannot represent non-integer value: "-1.1"');
|
$this->expectExceptionMessage('Int cannot represent non 32-bit signed integer value: Int cannot represent non-integer value: "-1.1"');
|
||||||
$intType->serialize('Int cannot represent non-integer value: "-1.1"');
|
$intType->serialize('Int cannot represent non-integer value: "-1.1"');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSerializesOutputIntCannotRepresentBiggerThan32Bits() : void
|
public function testSerializesOutputIntCannotRepresentBiggerThan32Bits() : void
|
||||||
@ -71,7 +70,6 @@ class ScalarSerializationTest extends TestCase
|
|||||||
$this->expectException(Error::class);
|
$this->expectException(Error::class);
|
||||||
$this->expectExceptionMessage('Int cannot represent non 32-bit signed integer value: 9876504321');
|
$this->expectExceptionMessage('Int cannot represent non 32-bit signed integer value: 9876504321');
|
||||||
$intType->serialize(9876504321);
|
$intType->serialize(9876504321);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSerializesOutputIntCannotRepresentLowerThan32Bits() : void
|
public function testSerializesOutputIntCannotRepresentLowerThan32Bits() : void
|
||||||
@ -104,7 +102,6 @@ class ScalarSerializationTest extends TestCase
|
|||||||
$this->expectException(Error::class);
|
$this->expectException(Error::class);
|
||||||
$this->expectExceptionMessage('Int cannot represent non 32-bit signed integer value: one');
|
$this->expectExceptionMessage('Int cannot represent non 32-bit signed integer value: one');
|
||||||
$intType->serialize('one');
|
$intType->serialize('one');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSerializesOutputIntCannotRepresentEmptyString() : void
|
public function testSerializesOutputIntCannotRepresentEmptyString() : void
|
||||||
@ -189,14 +186,13 @@ class ScalarSerializationTest extends TestCase
|
|||||||
{
|
{
|
||||||
$boolType = Type::boolean();
|
$boolType = Type::boolean();
|
||||||
|
|
||||||
$this->assertSame(true, $boolType->serialize('string'));
|
$this->assertTrue($boolType->serialize('string'));
|
||||||
$this->assertSame(false, $boolType->serialize(''));
|
$this->assertFalse($boolType->serialize(''));
|
||||||
$this->assertSame(true, $boolType->serialize('1'));
|
$this->assertTrue($boolType->serialize('1'));
|
||||||
$this->assertSame(true, $boolType->serialize(1));
|
$this->assertTrue($boolType->serialize(1));
|
||||||
$this->assertSame(false, $boolType->serialize(0));
|
$this->assertFalse($boolType->serialize(0));
|
||||||
$this->assertSame(true, $boolType->serialize(true));
|
$this->assertTrue($boolType->serialize(true));
|
||||||
$this->assertSame(false, $boolType->serialize(false));
|
$this->assertFalse($boolType->serialize(false));
|
||||||
|
|
||||||
// TODO: how should it behave on '0'?
|
// TODO: how should it behave on '0'?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Type;
|
namespace GraphQL\Tests\Type;
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
@ -12,14 +15,19 @@ use PHPUnit\Framework\TestCase;
|
|||||||
|
|
||||||
class SchemaTest extends TestCase
|
class SchemaTest extends TestCase
|
||||||
{
|
{
|
||||||
|
/** @var InterfaceType */
|
||||||
private $interfaceType;
|
private $interfaceType;
|
||||||
|
|
||||||
|
/** @var ObjectType */
|
||||||
private $implementingType;
|
private $implementingType;
|
||||||
|
|
||||||
|
/** @var InputObjectType */
|
||||||
private $directiveInputType;
|
private $directiveInputType;
|
||||||
|
|
||||||
|
/** @var InputObjectType */
|
||||||
private $wrappedDirectiveInputType;
|
private $wrappedDirectiveInputType;
|
||||||
|
|
||||||
|
/** @var Directive */
|
||||||
private $directive;
|
private $directive;
|
||||||
|
|
||||||
/** @var Schema */
|
/** @var Schema */
|
||||||
@ -35,9 +43,14 @@ class SchemaTest extends TestCase
|
|||||||
$this->implementingType = new ObjectType([
|
$this->implementingType = new ObjectType([
|
||||||
'name' => 'Object',
|
'name' => 'Object',
|
||||||
'interfaces' => [$this->interfaceType],
|
'interfaces' => [$this->interfaceType],
|
||||||
'fields' => ['fieldName' => ['type' => Type::string(), 'resolve' => function () {
|
'fields' => [
|
||||||
|
'fieldName' => [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'resolve' => function () {
|
||||||
return '';
|
return '';
|
||||||
}]],
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->directiveInputType = new InputObjectType([
|
$this->directiveInputType = new InputObjectType([
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace GraphQL\Tests\Type;
|
|
||||||
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
|
||||||
use GraphQL\Type\Definition\Type;
|
|
||||||
|
|
||||||
class MyCustomType extends ObjectType
|
|
||||||
{
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$config = [
|
|
||||||
'fields' => [
|
|
||||||
'a' => Type::string()
|
|
||||||
]
|
|
||||||
];
|
|
||||||
parent::__construct($config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: named OtherCustom vs OtherCustomType intentionally
|
|
||||||
class OtherCustom extends ObjectType
|
|
||||||
{
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$config = [
|
|
||||||
'fields' => [
|
|
||||||
'b' => Type::string()
|
|
||||||
]
|
|
||||||
];
|
|
||||||
parent::__construct($config);
|
|
||||||
}
|
|
||||||
}
|
|
21
tests/Type/TestClasses/MyCustomType.php
Normal file
21
tests/Type/TestClasses/MyCustomType.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Type\TestClasses;
|
||||||
|
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
|
||||||
|
class MyCustomType extends ObjectType
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$config = [
|
||||||
|
'fields' => [
|
||||||
|
'a' => Type::string(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
parent::__construct($config);
|
||||||
|
}
|
||||||
|
}
|
24
tests/Type/TestClasses/OtherCustom.php
Normal file
24
tests/Type/TestClasses/OtherCustom.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Type\TestClasses;
|
||||||
|
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: named OtherCustom vs OtherCustomType intentionally
|
||||||
|
*/
|
||||||
|
class OtherCustom extends ObjectType
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$config = [
|
||||||
|
'fields' => [
|
||||||
|
'b' => Type::string(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
parent::__construct($config);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Type;
|
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Type;
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
@ -9,52 +11,35 @@ use GraphQL\Type\Definition\ObjectType;
|
|||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Type\Schema;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function lcfirst;
|
||||||
|
|
||||||
class TypeLoaderTest extends TestCase
|
class TypeLoaderTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $query;
|
private $query;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $mutation;
|
private $mutation;
|
||||||
|
|
||||||
/**
|
/** @var InterfaceType */
|
||||||
* @var InterfaceType
|
|
||||||
*/
|
|
||||||
private $node;
|
private $node;
|
||||||
|
|
||||||
/**
|
/** @var InterfaceType */
|
||||||
* @var InterfaceType
|
|
||||||
*/
|
|
||||||
private $content;
|
private $content;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $blogStory;
|
private $blogStory;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $postStoryMutation;
|
private $postStoryMutation;
|
||||||
|
|
||||||
/**
|
/** @var InputObjectType */
|
||||||
* @var InputObjectType
|
|
||||||
*/
|
|
||||||
private $postStoryMutationInput;
|
private $postStoryMutationInput;
|
||||||
|
|
||||||
/**
|
/** @var callable */
|
||||||
* @var callable
|
|
||||||
*/
|
|
||||||
private $typeLoader;
|
private $typeLoader;
|
||||||
|
|
||||||
/**
|
/** @var string[] */
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $calls;
|
private $calls;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -63,35 +48,40 @@ class TypeLoaderTest extends TestCase
|
|||||||
|
|
||||||
$this->node = new InterfaceType([
|
$this->node = new InterfaceType([
|
||||||
'name' => 'Node',
|
'name' => 'Node',
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
$this->calls[] = 'Node.fields';
|
$this->calls[] = 'Node.fields';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => Type::string()
|
'id' => Type::string(),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
'resolveType' => function() {}
|
'resolveType' => function () {
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->content = new InterfaceType([
|
$this->content = new InterfaceType([
|
||||||
'name' => 'Content',
|
'name' => 'Content',
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
$this->calls[] = 'Content.fields';
|
$this->calls[] = 'Content.fields';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'title' => Type::string(),
|
'title' => Type::string(),
|
||||||
'body' => Type::string(),
|
'body' => Type::string(),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
'resolveType' => function() {}
|
'resolveType' => function () {
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->blogStory = new ObjectType([
|
$this->blogStory = new ObjectType([
|
||||||
'name' => 'BlogStory',
|
'name' => 'BlogStory',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node,
|
$this->node,
|
||||||
$this->content
|
$this->content,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
$this->calls[] = 'BlogStory.fields';
|
$this->calls[] = 'BlogStory.fields';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
$this->node->getField('id'),
|
||||||
$this->content->getField('title'),
|
$this->content->getField('title'),
|
||||||
@ -102,36 +92,38 @@ class TypeLoaderTest extends TestCase
|
|||||||
|
|
||||||
$this->query = new ObjectType([
|
$this->query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
$this->calls[] = 'Query.fields';
|
$this->calls[] = 'Query.fields';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'latestContent' => $this->content,
|
'latestContent' => $this->content,
|
||||||
'node' => $this->node,
|
'node' => $this->node,
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->mutation = new ObjectType([
|
$this->mutation = new ObjectType([
|
||||||
'name' => 'Mutation',
|
'name' => 'Mutation',
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
$this->calls[] = 'Mutation.fields';
|
$this->calls[] = 'Mutation.fields';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'postStory' => [
|
'postStory' => [
|
||||||
'type' => $this->postStoryMutation,
|
'type' => $this->postStoryMutation,
|
||||||
'args' => [
|
'args' => [
|
||||||
'input' => Type::nonNull($this->postStoryMutationInput),
|
'input' => Type::nonNull($this->postStoryMutationInput),
|
||||||
'clientRequestId' => Type::string()
|
'clientRequestId' => Type::string(),
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->postStoryMutation = new ObjectType([
|
$this->postStoryMutation = new ObjectType([
|
||||||
'name' => 'PostStoryMutation',
|
'name' => 'PostStoryMutation',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'story' => $this->blogStory
|
'story' => $this->blogStory,
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->postStoryMutationInput = new InputObjectType([
|
$this->postStoryMutationInput = new InputObjectType([
|
||||||
@ -140,14 +132,15 @@ class TypeLoaderTest extends TestCase
|
|||||||
'title' => Type::string(),
|
'title' => Type::string(),
|
||||||
'body' => Type::string(),
|
'body' => Type::string(),
|
||||||
'author' => Type::id(),
|
'author' => Type::id(),
|
||||||
'category' => Type::id()
|
'category' => Type::id(),
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->typeLoader = function($name) {
|
$this->typeLoader = function ($name) {
|
||||||
$this->calls[] = $name;
|
$this->calls[] = $name;
|
||||||
$prop = lcfirst($name);
|
$prop = lcfirst($name);
|
||||||
return isset($this->{$prop}) ? $this->{$prop} : null;
|
|
||||||
|
return $this->{$prop} ?? null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,9 +150,10 @@ class TypeLoaderTest extends TestCase
|
|||||||
new Schema([
|
new Schema([
|
||||||
'query' => new ObjectType([
|
'query' => new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => ['a' => Type::string()]
|
'fields' => ['a' => Type::string()],
|
||||||
]),
|
]),
|
||||||
'typeLoader' => function() {}
|
'typeLoader' => function () {
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,9 +165,9 @@ class TypeLoaderTest extends TestCase
|
|||||||
new Schema([
|
new Schema([
|
||||||
'query' => new ObjectType([
|
'query' => new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => ['a' => Type::string()]
|
'fields' => ['a' => Type::string()],
|
||||||
]),
|
]),
|
||||||
'typeLoader' => []
|
'typeLoader' => [],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +176,7 @@ class TypeLoaderTest extends TestCase
|
|||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->query,
|
'query' => $this->query,
|
||||||
'mutation' => $this->mutation,
|
'mutation' => $this->mutation,
|
||||||
'types' => [$this->blogStory]
|
'types' => [$this->blogStory],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$expected = [
|
$expected = [
|
||||||
@ -220,7 +214,7 @@ class TypeLoaderTest extends TestCase
|
|||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->query,
|
'query' => $this->query,
|
||||||
'mutation' => $this->mutation,
|
'mutation' => $this->mutation,
|
||||||
'typeLoader' => $this->typeLoader
|
'typeLoader' => $this->typeLoader,
|
||||||
]);
|
]);
|
||||||
$this->assertEquals([], $this->calls);
|
$this->assertEquals([], $this->calls);
|
||||||
|
|
||||||
@ -245,7 +239,7 @@ class TypeLoaderTest extends TestCase
|
|||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->query,
|
'query' => $this->query,
|
||||||
'typeLoader' => $this->typeLoader
|
'typeLoader' => $this->typeLoader,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema->getType('Node');
|
$schema->getType('Node');
|
||||||
@ -259,7 +253,8 @@ class TypeLoaderTest extends TestCase
|
|||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->query,
|
'query' => $this->query,
|
||||||
'typeLoader' => function() {}
|
'typeLoader' => function () {
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->expectException(InvariantViolation::class);
|
$this->expectException(InvariantViolation::class);
|
||||||
@ -272,9 +267,9 @@ class TypeLoaderTest extends TestCase
|
|||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->query,
|
'query' => $this->query,
|
||||||
'typeLoader' => function() {
|
'typeLoader' => function () {
|
||||||
return new \stdClass();
|
return new \stdClass();
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->expectException(InvariantViolation::class);
|
$this->expectException(InvariantViolation::class);
|
||||||
@ -287,9 +282,9 @@ class TypeLoaderTest extends TestCase
|
|||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->query,
|
'query' => $this->query,
|
||||||
'typeLoader' => function() {
|
'typeLoader' => function () {
|
||||||
return $this->content;
|
return $this->content;
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->expectException(InvariantViolation::class);
|
$this->expectException(InvariantViolation::class);
|
||||||
@ -302,9 +297,9 @@ class TypeLoaderTest extends TestCase
|
|||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->query,
|
'query' => $this->query,
|
||||||
'typeLoader' => function() {
|
'typeLoader' => function () {
|
||||||
throw new \Exception("This is the exception we are looking for");
|
throw new \Exception('This is the exception we are looking for');
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->expectException(\Throwable::class);
|
$this->expectException(\Throwable::class);
|
||||||
@ -317,13 +312,13 @@ class TypeLoaderTest extends TestCase
|
|||||||
{
|
{
|
||||||
$withoutLoader = new Schema([
|
$withoutLoader = new Schema([
|
||||||
'query' => $this->query,
|
'query' => $this->query,
|
||||||
'mutation' => $this->mutation
|
'mutation' => $this->mutation,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$withLoader = new Schema([
|
$withLoader = new Schema([
|
||||||
'query' => $this->query,
|
'query' => $this->query,
|
||||||
'mutation' => $this->mutation,
|
'mutation' => $this->mutation,
|
||||||
'typeLoader' => $this->typeLoader
|
'typeLoader' => $this->typeLoader,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertSame($withoutLoader->getQueryType(), $withLoader->getQueryType());
|
$this->assertSame($withoutLoader->getQueryType(), $withLoader->getQueryType());
|
||||||
@ -337,7 +332,7 @@ class TypeLoaderTest extends TestCase
|
|||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $this->query,
|
'query' => $this->query,
|
||||||
'mutation' => $this->mutation,
|
'mutation' => $this->mutation,
|
||||||
'typeLoader' => $this->typeLoader
|
'typeLoader' => $this->typeLoader,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$type = $schema->getType('ID');
|
$type = $schema->getType('ID');
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Utils;
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
@ -9,7 +12,6 @@ use PHPUnit\Framework\TestCase;
|
|||||||
class AssertValidNameTest extends TestCase
|
class AssertValidNameTest extends TestCase
|
||||||
{
|
{
|
||||||
// Describe: assertValidName()
|
// Describe: assertValidName()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('throws for use of leading double underscores')
|
* @see it('throws for use of leading double underscores')
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Utils;
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
use GraphQL\Language\AST\BooleanValueNode;
|
use GraphQL\Language\AST\BooleanValueNode;
|
||||||
@ -16,10 +19,12 @@ use GraphQL\Type\Definition\InputObjectType;
|
|||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Utils\AST;
|
use GraphQL\Utils\AST;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
class AstFromValueTest extends TestCase
|
class AstFromValueTest extends TestCase
|
||||||
{
|
{
|
||||||
// Describe: astFromValue
|
/** @var stdClass */
|
||||||
|
private $complexValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('converts boolean values to ASTs')
|
* @see it('converts boolean values to ASTs')
|
||||||
@ -31,8 +36,14 @@ class AstFromValueTest extends TestCase
|
|||||||
$this->assertEquals(new NullValueNode([]), AST::astFromValue(null, Type::boolean()));
|
$this->assertEquals(new NullValueNode([]), AST::astFromValue(null, Type::boolean()));
|
||||||
$this->assertEquals(new BooleanValueNode(['value' => false]), AST::astFromValue(0, Type::boolean()));
|
$this->assertEquals(new BooleanValueNode(['value' => false]), AST::astFromValue(0, Type::boolean()));
|
||||||
$this->assertEquals(new BooleanValueNode(['value' => true]), AST::astFromValue(1, Type::boolean()));
|
$this->assertEquals(new BooleanValueNode(['value' => true]), AST::astFromValue(1, Type::boolean()));
|
||||||
$this->assertEquals(new BooleanValueNode(['value' => false]), AST::astFromValue(0, Type::nonNull(Type::boolean())));
|
$this->assertEquals(
|
||||||
$this->assertEquals(null, AST::astFromValue(null, Type::nonNull(Type::boolean()))); // Note: null means that AST cannot
|
new BooleanValueNode(['value' => false]),
|
||||||
|
AST::astFromValue(0, Type::nonNull(Type::boolean()))
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
null,
|
||||||
|
AST::astFromValue(null, Type::nonNull(Type::boolean()))
|
||||||
|
); // Note: null means that AST cannot
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,7 +70,10 @@ class AstFromValueTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->expectException(\Throwable::class);
|
$this->expectException(\Throwable::class);
|
||||||
$this->expectExceptionMessage('Int cannot represent non 32-bit signed integer value: 1.0E+40');
|
$this->expectExceptionMessage('Int cannot represent non 32-bit signed integer value: 1.0E+40');
|
||||||
AST::astFromValue(1e40, Type::int()); // Note: js version will produce 1e+40, both values are valid GraphQL floats
|
AST::astFromValue(
|
||||||
|
1e40,
|
||||||
|
Type::int()
|
||||||
|
); // Note: js version will produce 1e+40, both values are valid GraphQL floats
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,7 +126,7 @@ class AstFromValueTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testDoesNotConvertsNonNullValuestoNullValue() : void
|
public function testDoesNotConvertsNonNullValuestoNullValue() : void
|
||||||
{
|
{
|
||||||
$this->assertSame(null, AST::astFromValue(null, Type::nonNull(Type::boolean())));
|
$this->assertNull(AST::astFromValue(null, Type::nonNull(Type::boolean())));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,99 +135,16 @@ class AstFromValueTest extends TestCase
|
|||||||
public function testConvertsStringValuesToEnumASTsIfPossible() : void
|
public function testConvertsStringValuesToEnumASTsIfPossible() : void
|
||||||
{
|
{
|
||||||
$this->assertEquals(new EnumValueNode(['value' => 'HELLO']), AST::astFromValue('HELLO', $this->myEnum()));
|
$this->assertEquals(new EnumValueNode(['value' => 'HELLO']), AST::astFromValue('HELLO', $this->myEnum()));
|
||||||
$this->assertEquals(new EnumValueNode(['value' => 'COMPLEX']), AST::astFromValue($this->complexValue(), $this->myEnum()));
|
$this->assertEquals(
|
||||||
|
new EnumValueNode(['value' => 'COMPLEX']),
|
||||||
|
AST::astFromValue($this->complexValue(), $this->myEnum())
|
||||||
|
);
|
||||||
|
|
||||||
// Note: case sensitive
|
// Note: case sensitive
|
||||||
$this->assertEquals(null, AST::astFromValue('hello', $this->myEnum()));
|
$this->assertNull(AST::astFromValue('hello', $this->myEnum()));
|
||||||
|
|
||||||
// Note: Not a valid enum value
|
// Note: Not a valid enum value
|
||||||
$this->assertEquals(null, AST::astFromValue('VALUE', $this->myEnum()));
|
$this->assertNull(AST::astFromValue('VALUE', $this->myEnum()));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see it('converts array values to List ASTs')
|
|
||||||
*/
|
|
||||||
public function testConvertsArrayValuesToListASTs() : void
|
|
||||||
{
|
|
||||||
$value1 = new ListValueNode([
|
|
||||||
'values' => [
|
|
||||||
new StringValueNode(['value' => 'FOO']),
|
|
||||||
new StringValueNode(['value' => 'BAR'])
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
$this->assertEquals($value1, AST::astFromValue(['FOO', 'BAR'], Type::listOf(Type::string())));
|
|
||||||
|
|
||||||
$value2 = new ListValueNode([
|
|
||||||
'values' => [
|
|
||||||
new EnumValueNode(['value' => 'HELLO']),
|
|
||||||
new EnumValueNode(['value' => 'GOODBYE']),
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
$this->assertEquals($value2, AST::astFromValue(['HELLO', 'GOODBYE'], Type::listOf($this->myEnum())));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see it('converts list singletons')
|
|
||||||
*/
|
|
||||||
public function testConvertsListSingletons() : void
|
|
||||||
{
|
|
||||||
$this->assertEquals(new StringValueNode(['value' => 'FOO']), AST::astFromValue('FOO', Type::listOf(Type::string())));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see it('converts input objects')
|
|
||||||
*/
|
|
||||||
public function testConvertsInputObjects() : void
|
|
||||||
{
|
|
||||||
$inputObj = new InputObjectType([
|
|
||||||
'name' => 'MyInputObj',
|
|
||||||
'fields' => [
|
|
||||||
'foo' => Type::float(),
|
|
||||||
'bar' => $this->myEnum()
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$expected = new ObjectValueNode([
|
|
||||||
'fields' => [
|
|
||||||
$this->objectField('foo', new IntValueNode(['value' => '3'])),
|
|
||||||
$this->objectField('bar', new EnumValueNode(['value' => 'HELLO']))
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$data = ['foo' => 3, 'bar' => 'HELLO'];
|
|
||||||
$this->assertEquals($expected, AST::astFromValue($data, $inputObj));
|
|
||||||
$this->assertEquals($expected, AST::astFromValue((object) $data, $inputObj));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see it('converts input objects with explicit nulls')
|
|
||||||
*/
|
|
||||||
public function testConvertsInputObjectsWithExplicitNulls() : void
|
|
||||||
{
|
|
||||||
$inputObj = new InputObjectType([
|
|
||||||
'name' => 'MyInputObj',
|
|
||||||
'fields' => [
|
|
||||||
'foo' => Type::float(),
|
|
||||||
'bar' => $this->myEnum()
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->assertEquals(new ObjectValueNode([
|
|
||||||
'fields' => [
|
|
||||||
$this->objectField('foo', new NullValueNode([]))
|
|
||||||
]
|
|
||||||
]), AST::astFromValue(['foo' => null], $inputObj));
|
|
||||||
}
|
|
||||||
|
|
||||||
private $complexValue;
|
|
||||||
|
|
||||||
private function complexValue()
|
|
||||||
{
|
|
||||||
if (!$this->complexValue) {
|
|
||||||
$this->complexValue = new \stdClass();
|
|
||||||
$this->complexValue->someArbitrary = 'complexValue';
|
|
||||||
}
|
|
||||||
return $this->complexValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -226,21 +157,111 @@ class AstFromValueTest extends TestCase
|
|||||||
'values' => [
|
'values' => [
|
||||||
'HELLO' => [],
|
'HELLO' => [],
|
||||||
'GOODBYE' => [],
|
'GOODBYE' => [],
|
||||||
'COMPLEX' => ['value' => $this->complexValue()]
|
'COMPLEX' => ['value' => $this->complexValue()],
|
||||||
]
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function complexValue()
|
||||||
|
{
|
||||||
|
if (! $this->complexValue) {
|
||||||
|
$this->complexValue = new \stdClass();
|
||||||
|
$this->complexValue->someArbitrary = 'complexValue';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->complexValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see it('converts array values to List ASTs')
|
||||||
|
*/
|
||||||
|
public function testConvertsArrayValuesToListASTs() : void
|
||||||
|
{
|
||||||
|
$value1 = new ListValueNode([
|
||||||
|
'values' => [
|
||||||
|
new StringValueNode(['value' => 'FOO']),
|
||||||
|
new StringValueNode(['value' => 'BAR']),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$this->assertEquals($value1, AST::astFromValue(['FOO', 'BAR'], Type::listOf(Type::string())));
|
||||||
|
|
||||||
|
$value2 = new ListValueNode([
|
||||||
|
'values' => [
|
||||||
|
new EnumValueNode(['value' => 'HELLO']),
|
||||||
|
new EnumValueNode(['value' => 'GOODBYE']),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$this->assertEquals($value2, AST::astFromValue(['HELLO', 'GOODBYE'], Type::listOf($this->myEnum())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see it('converts list singletons')
|
||||||
|
*/
|
||||||
|
public function testConvertsListSingletons() : void
|
||||||
|
{
|
||||||
|
$this->assertEquals(
|
||||||
|
new StringValueNode(['value' => 'FOO']),
|
||||||
|
AST::astFromValue('FOO', Type::listOf(Type::string()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see it('converts input objects')
|
||||||
|
*/
|
||||||
|
public function testConvertsInputObjects() : void
|
||||||
|
{
|
||||||
|
$inputObj = new InputObjectType([
|
||||||
|
'name' => 'MyInputObj',
|
||||||
|
'fields' => [
|
||||||
|
'foo' => Type::float(),
|
||||||
|
'bar' => $this->myEnum(),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$expected = new ObjectValueNode([
|
||||||
|
'fields' => [
|
||||||
|
$this->objectField('foo', new IntValueNode(['value' => '3'])),
|
||||||
|
$this->objectField('bar', new EnumValueNode(['value' => 'HELLO'])),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = ['foo' => 3, 'bar' => 'HELLO'];
|
||||||
|
$this->assertEquals($expected, AST::astFromValue($data, $inputObj));
|
||||||
|
$this->assertEquals($expected, AST::astFromValue((object) $data, $inputObj));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
* @return ObjectFieldNode
|
||||||
|
*/
|
||||||
|
private function objectField(string $name, $value)
|
||||||
|
{
|
||||||
|
return new ObjectFieldNode([
|
||||||
|
'name' => new NameNode(['value' => $name]),
|
||||||
|
'value' => $value,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $name
|
* @see it('converts input objects with explicit nulls')
|
||||||
* @param $value
|
|
||||||
* @return ObjectFieldNode
|
|
||||||
*/
|
*/
|
||||||
private function objectField($name, $value)
|
public function testConvertsInputObjectsWithExplicitNulls() : void
|
||||||
{
|
{
|
||||||
return new ObjectFieldNode([
|
$inputObj = new InputObjectType([
|
||||||
'name' => new NameNode(['value' => $name]),
|
'name' => 'MyInputObj',
|
||||||
'value' => $value
|
'fields' => [
|
||||||
|
'foo' => Type::float(),
|
||||||
|
'bar' => $this->myEnum(),
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new ObjectValueNode([
|
||||||
|
'fields' => [
|
||||||
|
$this->objectField('foo', new NullValueNode([])),
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
AST::astFromValue(['foo' => null], $inputObj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Utils;
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
@ -8,14 +11,6 @@ use PHPUnit\Framework\TestCase;
|
|||||||
class AstFromValueUntypedTest extends TestCase
|
class AstFromValueUntypedTest extends TestCase
|
||||||
{
|
{
|
||||||
// Describe: valueFromASTUntyped
|
// Describe: valueFromASTUntyped
|
||||||
|
|
||||||
private function assertTestCase($valueText, $expected, array $variables = null) {
|
|
||||||
$this->assertEquals(
|
|
||||||
$expected,
|
|
||||||
AST::valueFromASTUntyped(Parser::parseValue($valueText), $variables)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('parses simple values')
|
* @see it('parses simple values')
|
||||||
*/
|
*/
|
||||||
@ -29,6 +24,17 @@ class AstFromValueUntypedTest extends TestCase
|
|||||||
$this->assertTestCase('abc123', 'abc123');
|
$this->assertTestCase('abc123', 'abc123');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[]|null $variables
|
||||||
|
*/
|
||||||
|
private function assertTestCase($valueText, $expected, ?array $variables = null) : void
|
||||||
|
{
|
||||||
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
AST::valueFromASTUntyped(Parser::parseValue($valueText), $variables)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('parses lists of values')
|
* @see it('parses lists of values')
|
||||||
*/
|
*/
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Utils;
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
@ -8,24 +11,19 @@ use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
|
|||||||
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
|
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\Printer;
|
use GraphQL\Language\Printer;
|
||||||
|
use GraphQL\Type\Definition\Directive;
|
||||||
use GraphQL\Type\Definition\EnumType;
|
use GraphQL\Type\Definition\EnumType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Utils\BuildSchema;
|
use GraphQL\Utils\BuildSchema;
|
||||||
use GraphQL\Utils\SchemaPrinter;
|
use GraphQL\Utils\SchemaPrinter;
|
||||||
use GraphQL\Type\Definition\Directive;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use function array_keys;
|
||||||
|
use function count;
|
||||||
|
|
||||||
class BuildSchemaTest extends TestCase
|
class BuildSchemaTest extends TestCase
|
||||||
{
|
{
|
||||||
// Describe: Schema Builder
|
// Describe: Schema Builder
|
||||||
|
|
||||||
private function cycleOutput($body, $options = [])
|
|
||||||
{
|
|
||||||
$ast = Parser::parse($body);
|
|
||||||
$schema = BuildSchema::buildAST($ast, null, $options);
|
|
||||||
return "\n" . SchemaPrinter::doPrint($schema, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('can use built schema for limited execution')
|
* @see it('can use built schema for limited execution')
|
||||||
*/
|
*/
|
||||||
@ -46,16 +44,16 @@ class BuildSchemaTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testBuildSchemaDirectlyFromSource() : void
|
public function testBuildSchemaDirectlyFromSource() : void
|
||||||
{
|
{
|
||||||
$schema = BuildSchema::build("
|
$schema = BuildSchema::build('
|
||||||
type Query {
|
type Query {
|
||||||
add(x: Int, y: Int): Int
|
add(x: Int, y: Int): Int
|
||||||
}
|
}
|
||||||
");
|
');
|
||||||
|
|
||||||
$root = [
|
$root = [
|
||||||
'add' => function ($root, $args) {
|
'add' => function ($root, $args) {
|
||||||
return $args['x'] + $args['y'];
|
return $args['x'] + $args['y'];
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = GraphQL::executeQuery(
|
$result = GraphQL::executeQuery(
|
||||||
@ -84,6 +82,14 @@ type HelloScalars {
|
|||||||
$this->assertEquals($output, $body);
|
$this->assertEquals($output, $body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function cycleOutput($body, $options = [])
|
||||||
|
{
|
||||||
|
$ast = Parser::parse($body);
|
||||||
|
$schema = BuildSchema::buildAST($ast, null, $options);
|
||||||
|
|
||||||
|
return "\n" . SchemaPrinter::doPrint($schema, $options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('With directives')
|
* @see it('With directives')
|
||||||
*/
|
*/
|
||||||
@ -159,7 +165,7 @@ type Query {
|
|||||||
str: String
|
str: String
|
||||||
}
|
}
|
||||||
';
|
';
|
||||||
$output = $this->cycleOutput($body, [ 'commentDescriptions' => true ]);
|
$output = $this->cycleOutput($body, ['commentDescriptions' => true]);
|
||||||
$this->assertEquals($body, $output);
|
$this->assertEquals($body, $output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,16 +473,16 @@ type WorldTwo {
|
|||||||
[
|
[
|
||||||
'length' => 5,
|
'length' => 5,
|
||||||
'__typename' => 'Banana',
|
'__typename' => 'Banana',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'fruits' => [
|
'fruits' => [
|
||||||
['color' => 'green'],
|
['color' => 'green'],
|
||||||
['length' => 5],
|
['length' => 5],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = GraphQL::executeQuery($schema, $query, $root);
|
$result = GraphQL::executeQuery($schema, $query, $root);
|
||||||
@ -531,16 +537,16 @@ type WorldTwo {
|
|||||||
'name' => 'R2-D2',
|
'name' => 'R2-D2',
|
||||||
'primaryFunction' => 'Astromech',
|
'primaryFunction' => 'Astromech',
|
||||||
'__typename' => 'Droid',
|
'__typename' => 'Droid',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'characters' => [
|
'characters' => [
|
||||||
['name' => 'Han Solo', 'totalCredits' => 10],
|
['name' => 'Han Solo', 'totalCredits' => 10],
|
||||||
['name' => 'R2-D2', 'primaryFunction' => 'Astromech'],
|
['name' => 'R2-D2', 'primaryFunction' => 'Astromech'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = GraphQL::executeQuery($schema, $query, $root);
|
$result = GraphQL::executeQuery($schema, $query, $root);
|
||||||
@ -813,9 +819,15 @@ type Query {
|
|||||||
$testField = $query->getField('testField');
|
$testField = $query->getField('testField');
|
||||||
$this->assertEquals('testField(testArg: TestInput): TestUnion', Printer::doPrint($testField->astNode));
|
$this->assertEquals('testField(testArg: TestInput): TestUnion', Printer::doPrint($testField->astNode));
|
||||||
$this->assertEquals('testArg: TestInput', Printer::doPrint($testField->args[0]->astNode));
|
$this->assertEquals('testArg: TestInput', Printer::doPrint($testField->args[0]->astNode));
|
||||||
$this->assertEquals('testInputField: TestEnum', Printer::doPrint($testInput->getField('testInputField')->astNode));
|
$this->assertEquals(
|
||||||
|
'testInputField: TestEnum',
|
||||||
|
Printer::doPrint($testInput->getField('testInputField')->astNode)
|
||||||
|
);
|
||||||
$this->assertEquals('TEST_VALUE', Printer::doPrint($testEnum->getValue('TEST_VALUE')->astNode));
|
$this->assertEquals('TEST_VALUE', Printer::doPrint($testEnum->getValue('TEST_VALUE')->astNode));
|
||||||
$this->assertEquals('interfaceField: String', Printer::doPrint($testInterface->getField('interfaceField')->astNode));
|
$this->assertEquals(
|
||||||
|
'interfaceField: String',
|
||||||
|
Printer::doPrint($testInterface->getField('interfaceField')->astNode)
|
||||||
|
);
|
||||||
$this->assertEquals('interfaceField: String', Printer::doPrint($testType->getField('interfaceField')->astNode));
|
$this->assertEquals('interfaceField: String', Printer::doPrint($testType->getField('interfaceField')->astNode));
|
||||||
$this->assertEquals('arg: TestScalar', Printer::doPrint($testDirective->args[0]->astNode));
|
$this->assertEquals('arg: TestScalar', Printer::doPrint($testDirective->args[0]->astNode));
|
||||||
}
|
}
|
||||||
@ -1184,9 +1196,10 @@ interface Hello {
|
|||||||
$decorated = [];
|
$decorated = [];
|
||||||
$calls = [];
|
$calls = [];
|
||||||
|
|
||||||
$typeConfigDecorator = function($defaultConfig, $node, $allNodesMap) use (&$decorated, &$calls) {
|
$typeConfigDecorator = function ($defaultConfig, $node, $allNodesMap) use (&$decorated, &$calls) {
|
||||||
$decorated[] = $defaultConfig['name'];
|
$decorated[] = $defaultConfig['name'];
|
||||||
$calls[] = [$defaultConfig, $node, $allNodesMap];
|
$calls[] = [$defaultConfig, $node, $allNodesMap];
|
||||||
|
|
||||||
return ['description' => 'My description of ' . $node->name->value] + $defaultConfig;
|
return ['description' => 'My description of ' . $node->name->value] + $defaultConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1204,19 +1217,21 @@ interface Hello {
|
|||||||
$this->assertEquals(array_keys($allNodesMap), ['Query', 'Color', 'Hello']);
|
$this->assertEquals(array_keys($allNodesMap), ['Query', 'Color', 'Hello']);
|
||||||
$this->assertEquals('My description of Query', $schema->getType('Query')->description);
|
$this->assertEquals('My description of Query', $schema->getType('Query')->description);
|
||||||
|
|
||||||
|
|
||||||
list($defaultConfig, $node, $allNodesMap) = $calls[1];
|
list($defaultConfig, $node, $allNodesMap) = $calls[1];
|
||||||
$this->assertInstanceOf(EnumTypeDefinitionNode::class, $node);
|
$this->assertInstanceOf(EnumTypeDefinitionNode::class, $node);
|
||||||
$this->assertEquals('Color', $defaultConfig['name']);
|
$this->assertEquals('Color', $defaultConfig['name']);
|
||||||
$enumValue = [
|
$enumValue = [
|
||||||
'description' => '',
|
'description' => '',
|
||||||
'deprecationReason' => ''
|
'deprecationReason' => '',
|
||||||
];
|
];
|
||||||
$this->assertArraySubset([
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
'RED' => $enumValue,
|
'RED' => $enumValue,
|
||||||
'GREEN' => $enumValue,
|
'GREEN' => $enumValue,
|
||||||
'BLUE' => $enumValue,
|
'BLUE' => $enumValue,
|
||||||
], $defaultConfig['values']);
|
],
|
||||||
|
$defaultConfig['values']
|
||||||
|
);
|
||||||
$this->assertCount(4, $defaultConfig); // 3 + astNode
|
$this->assertCount(4, $defaultConfig); // 3 + astNode
|
||||||
$this->assertEquals(array_keys($allNodesMap), ['Query', 'Color', 'Hello']);
|
$this->assertEquals(array_keys($allNodesMap), ['Query', 'Color', 'Hello']);
|
||||||
$this->assertEquals('My description of Color', $schema->getType('Color')->description);
|
$this->assertEquals('My description of Color', $schema->getType('Color')->description);
|
||||||
@ -1261,8 +1276,9 @@ type World implements Hello {
|
|||||||
$doc = Parser::parse($body);
|
$doc = Parser::parse($body);
|
||||||
$created = [];
|
$created = [];
|
||||||
|
|
||||||
$typeConfigDecorator = function($config, $node) use (&$created) {
|
$typeConfigDecorator = function ($config, $node) use (&$created) {
|
||||||
$created[] = $node->name->value;
|
$created[] = $node->name->value;
|
||||||
|
|
||||||
return $config;
|
return $config;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1282,5 +1298,4 @@ type World implements Hello {
|
|||||||
$this->assertArrayHasKey('Hello', $types);
|
$this->assertArrayHasKey('Hello', $types);
|
||||||
$this->assertArrayHasKey('World', $types);
|
$this->assertArrayHasKey('World', $types);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Utils;
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
|
||||||
use GraphQL\Executor\Values;
|
|
||||||
use GraphQL\Type\Definition\EnumType;
|
use GraphQL\Type\Definition\EnumType;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
@ -12,7 +13,10 @@ use PHPUnit\Framework\TestCase;
|
|||||||
|
|
||||||
class CoerceValueTest extends TestCase
|
class CoerceValueTest extends TestCase
|
||||||
{
|
{
|
||||||
|
/** @var EnumType */
|
||||||
private $testEnum;
|
private $testEnum;
|
||||||
|
|
||||||
|
/** @var InputObjectType */
|
||||||
private $testInputObject;
|
private $testInputObject;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -34,9 +38,9 @@ class CoerceValueTest extends TestCase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: coerceValue
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Describe: coerceValue
|
||||||
|
*
|
||||||
* @see it('coercing an array to GraphQLString produces an error')
|
* @see it('coercing an array to GraphQLString produces an error')
|
||||||
*/
|
*/
|
||||||
public function testCoercingAnArrayToGraphQLStringProducesAnError() : void
|
public function testCoercingAnArrayToGraphQLStringProducesAnError() : void
|
||||||
@ -53,7 +57,17 @@ class CoerceValueTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: for GraphQLInt
|
/**
|
||||||
|
* Describe: for GraphQLInt
|
||||||
|
*/
|
||||||
|
private function expectError($result, $expected)
|
||||||
|
{
|
||||||
|
$this->assertInternalType('array', $result);
|
||||||
|
$this->assertInternalType('array', $result['errors']);
|
||||||
|
$this->assertCount(1, $result['errors']);
|
||||||
|
$this->assertEquals($expected, $result['errors'][0]->getMessage());
|
||||||
|
$this->assertEquals(Utils::undefined(), $result['value']);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('returns no error for int input')
|
* @see it('returns no error for int input')
|
||||||
@ -64,6 +78,13 @@ class CoerceValueTest extends TestCase
|
|||||||
$this->expectNoErrors($result);
|
$this->expectNoErrors($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function expectNoErrors($result)
|
||||||
|
{
|
||||||
|
$this->assertInternalType('array', $result);
|
||||||
|
$this->assertNull($result['errors']);
|
||||||
|
$this->assertNotEquals(Utils::undefined(), $result['value']);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('returns no error for negative int input')
|
* @see it('returns no error for negative int input')
|
||||||
*/
|
*/
|
||||||
@ -115,6 +136,8 @@ class CoerceValueTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe: for GraphQLFloat
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('returns a single error for char input')
|
* @see it('returns a single error for char input')
|
||||||
*/
|
*/
|
||||||
@ -139,8 +162,6 @@ class CoerceValueTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe: for GraphQLFloat
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('returns no error for int input')
|
* @see it('returns no error for int input')
|
||||||
*/
|
*/
|
||||||
@ -189,6 +210,8 @@ class CoerceValueTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DESCRIBE: for GraphQLEnum
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('returns a single error for char input')
|
* @see it('returns a single error for char input')
|
||||||
*/
|
*/
|
||||||
@ -213,8 +236,6 @@ class CoerceValueTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DESCRIBE: for GraphQLEnum
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('returns no error for a known enum name')
|
* @see it('returns no error for a known enum name')
|
||||||
*/
|
*/
|
||||||
@ -229,6 +250,8 @@ class CoerceValueTest extends TestCase
|
|||||||
$this->assertEquals(123456789, $barResult['value']);
|
$this->assertEquals(123456789, $barResult['value']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DESCRIBE: for GraphQLInputObject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('results error for misspelled enum value')
|
* @see it('results error for misspelled enum value')
|
||||||
*/
|
*/
|
||||||
@ -250,8 +273,6 @@ class CoerceValueTest extends TestCase
|
|||||||
$this->expectError($result2, 'Expected type TestEnum.');
|
$this->expectError($result2, 'Expected type TestEnum.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// DESCRIBE: for GraphQLInputObject
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('returns no error for a valid input')
|
* @see it('returns no error for a valid input')
|
||||||
*/
|
*/
|
||||||
@ -277,7 +298,10 @@ class CoerceValueTest extends TestCase
|
|||||||
public function testReturnErrorForAnInvalidField() : void
|
public function testReturnErrorForAnInvalidField() : void
|
||||||
{
|
{
|
||||||
$result = Value::coerceValue(['foo' => 'abc'], $this->testInputObject);
|
$result = Value::coerceValue(['foo' => 'abc'], $this->testInputObject);
|
||||||
$this->expectError($result, 'Expected type Int at value.foo; Int cannot represent non 32-bit signed integer value: abc');
|
$this->expectError(
|
||||||
|
$result,
|
||||||
|
'Expected type Int at value.foo; Int cannot represent non 32-bit signed integer value: abc'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -286,10 +310,13 @@ class CoerceValueTest extends TestCase
|
|||||||
public function testReturnsMultipleErrorsForMultipleInvalidFields() : void
|
public function testReturnsMultipleErrorsForMultipleInvalidFields() : void
|
||||||
{
|
{
|
||||||
$result = Value::coerceValue(['foo' => 'abc', 'bar' => 'def'], $this->testInputObject);
|
$result = Value::coerceValue(['foo' => 'abc', 'bar' => 'def'], $this->testInputObject);
|
||||||
$this->assertEquals([
|
$this->assertEquals(
|
||||||
|
[
|
||||||
'Expected type Int at value.foo; Int cannot represent non 32-bit signed integer value: abc',
|
'Expected type Int at value.foo; Int cannot represent non 32-bit signed integer value: abc',
|
||||||
'Expected type Int at value.bar; Int cannot represent non 32-bit signed integer value: def',
|
'Expected type Int at value.bar; Int cannot represent non 32-bit signed integer value: def',
|
||||||
], $result['errors']);
|
],
|
||||||
|
$result['errors']
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -318,20 +345,4 @@ class CoerceValueTest extends TestCase
|
|||||||
$result = Value::coerceValue(['foo' => 123, 'bart' => 123], $this->testInputObject);
|
$result = Value::coerceValue(['foo' => 123, 'bart' => 123], $this->testInputObject);
|
||||||
$this->expectError($result, 'Field "bart" is not defined by type TestInputObject; did you mean bar?');
|
$this->expectError($result, 'Field "bart" is not defined by type TestInputObject; did you mean bar?');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function expectNoErrors($result)
|
|
||||||
{
|
|
||||||
$this->assertInternalType('array', $result);
|
|
||||||
$this->assertNull($result['errors']);
|
|
||||||
$this->assertNotEquals(Utils::undefined(), $result['value']);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function expectError($result, $expected) {
|
|
||||||
$this->assertInternalType('array', $result);
|
|
||||||
$this->assertInternalType('array', $result['errors']);
|
|
||||||
$this->assertCount(1, $result['errors']);
|
|
||||||
$this->assertEquals($expected, $result['errors'][0]->getMessage());
|
|
||||||
$this->assertEquals(Utils::undefined(), $result['value']);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Utils;
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
@ -12,72 +15,43 @@ use PHPUnit\Framework\TestCase;
|
|||||||
|
|
||||||
class ExtractTypesTest extends TestCase
|
class ExtractTypesTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $query;
|
private $query;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $mutation;
|
private $mutation;
|
||||||
|
|
||||||
/**
|
/** @var InterfaceType */
|
||||||
* @var InterfaceType
|
|
||||||
*/
|
|
||||||
private $node;
|
private $node;
|
||||||
|
|
||||||
/**
|
/** @var InterfaceType */
|
||||||
* @var InterfaceType
|
|
||||||
*/
|
|
||||||
private $content;
|
private $content;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $blogStory;
|
private $blogStory;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $link;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $video;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $videoMetadata;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $comment;
|
private $comment;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $user;
|
private $user;
|
||||||
|
|
||||||
/**
|
/** @var ObjectType */
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
private $category;
|
private $category;
|
||||||
|
|
||||||
/**
|
/** @var UnionType */
|
||||||
* @var UnionType
|
|
||||||
*/
|
|
||||||
private $mention;
|
private $mention;
|
||||||
|
|
||||||
|
/** @var ObjectType */
|
||||||
private $postStoryMutation;
|
private $postStoryMutation;
|
||||||
|
|
||||||
|
/** @var InputObjectType */
|
||||||
private $postStoryMutationInput;
|
private $postStoryMutationInput;
|
||||||
|
|
||||||
|
/** @var ObjectType */
|
||||||
private $postCommentMutation;
|
private $postCommentMutation;
|
||||||
|
|
||||||
|
/** @var InputObjectType */
|
||||||
private $postCommentMutationInput;
|
private $postCommentMutationInput;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -85,136 +59,136 @@ class ExtractTypesTest extends TestCase
|
|||||||
$this->node = new InterfaceType([
|
$this->node = new InterfaceType([
|
||||||
'name' => 'Node',
|
'name' => 'Node',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'id' => Type::string()
|
'id' => Type::string(),
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->content = new InterfaceType([
|
$this->content = new InterfaceType([
|
||||||
'name' => 'Content',
|
'name' => 'Content',
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
'title' => Type::string(),
|
'title' => Type::string(),
|
||||||
'body' => Type::string(),
|
'body' => Type::string(),
|
||||||
'author' => $this->user,
|
'author' => $this->user,
|
||||||
'comments' => Type::listOf($this->comment),
|
'comments' => Type::listOf($this->comment),
|
||||||
'categories' => Type::listOf($this->category)
|
'categories' => Type::listOf($this->category),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->blogStory = new ObjectType([
|
$this->blogStory = new ObjectType([
|
||||||
'name' => 'BlogStory',
|
'name' => 'BlogStory',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node,
|
$this->node,
|
||||||
$this->content
|
$this->content,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
$this->node->getField('id'),
|
||||||
$this->content->getField('title'),
|
$this->content->getField('title'),
|
||||||
$this->content->getField('body'),
|
$this->content->getField('body'),
|
||||||
$this->content->getField('author'),
|
$this->content->getField('author'),
|
||||||
$this->content->getField('comments'),
|
$this->content->getField('comments'),
|
||||||
$this->content->getField('categories')
|
$this->content->getField('categories'),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->link = new ObjectType([
|
new ObjectType([
|
||||||
'name' => 'Link',
|
'name' => 'Link',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node,
|
$this->node,
|
||||||
$this->content
|
$this->content,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
'id' => $this->node->getField('id'),
|
||||||
$this->content->getField('title'),
|
'title' => $this->content->getField('title'),
|
||||||
$this->content->getField('body'),
|
'body' => $this->content->getField('body'),
|
||||||
$this->content->getField('author'),
|
'author' => $this->content->getField('author'),
|
||||||
$this->content->getField('comments'),
|
'comments' => $this->content->getField('comments'),
|
||||||
$this->content->getField('categories'),
|
'categories' => $this->content->getField('categories'),
|
||||||
'url' => Type::string()
|
'url' => Type::string(),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->video = new ObjectType([
|
new ObjectType([
|
||||||
'name' => 'Video',
|
'name' => 'Video',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node,
|
$this->node,
|
||||||
$this->content
|
$this->content,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
'id' => $this->node->getField('id'),
|
||||||
$this->content->getField('title'),
|
'title' => $this->content->getField('title'),
|
||||||
$this->content->getField('body'),
|
'body' => $this->content->getField('body'),
|
||||||
$this->content->getField('author'),
|
'author' => $this->content->getField('author'),
|
||||||
$this->content->getField('comments'),
|
'comments' => $this->content->getField('comments'),
|
||||||
$this->content->getField('categories'),
|
'categories' => $this->content->getField('categories'),
|
||||||
'streamUrl' => Type::string(),
|
'streamUrl' => Type::string(),
|
||||||
'downloadUrl' => Type::string(),
|
'downloadUrl' => Type::string(),
|
||||||
'metadata' => $this->videoMetadata = new ObjectType([
|
'metadata' => new ObjectType([
|
||||||
'name' => 'VideoMetadata',
|
'name' => 'VideoMetadata',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'lat' => Type::float(),
|
'lat' => Type::float(),
|
||||||
'lng' => Type::float()
|
'lng' => Type::float(),
|
||||||
]
|
],
|
||||||
])
|
]),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->comment = new ObjectType([
|
$this->comment = new ObjectType([
|
||||||
'name' => 'Comment',
|
'name' => 'Comment',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node
|
$this->node,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
'id' => $this->node->getField('id'),
|
||||||
'author' => $this->user,
|
'author' => $this->user,
|
||||||
'text' => Type::string(),
|
'text' => Type::string(),
|
||||||
'replies' => Type::listOf($this->comment),
|
'replies' => Type::listOf($this->comment),
|
||||||
'parent' => $this->comment,
|
'parent' => $this->comment,
|
||||||
'content' => $this->content
|
'content' => $this->content,
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->user = new ObjectType([
|
$this->user = new ObjectType([
|
||||||
'name' => 'User',
|
'name' => 'User',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node
|
$this->node,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
'id' => $this->node->getField('id'),
|
||||||
'name' => Type::string(),
|
'name' => Type::string(),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->category = new ObjectType([
|
$this->category = new ObjectType([
|
||||||
'name' => 'Category',
|
'name' => 'Category',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
$this->node
|
$this->node,
|
||||||
],
|
],
|
||||||
'fields' => function() {
|
'fields' => function () {
|
||||||
return [
|
return [
|
||||||
$this->node->getField('id'),
|
'id' => $this->node->getField('id'),
|
||||||
'name' => Type::string()
|
'name' => Type::string(),
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->mention = new UnionType([
|
$this->mention = new UnionType([
|
||||||
'name' => 'Mention',
|
'name' => 'Mention',
|
||||||
'types' => [
|
'types' => [
|
||||||
$this->user,
|
$this->user,
|
||||||
$this->category
|
$this->category,
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->query = new ObjectType([
|
$this->query = new ObjectType([
|
||||||
@ -223,8 +197,18 @@ class ExtractTypesTest extends TestCase
|
|||||||
'viewer' => $this->user,
|
'viewer' => $this->user,
|
||||||
'latestContent' => $this->content,
|
'latestContent' => $this->content,
|
||||||
'node' => $this->node,
|
'node' => $this->node,
|
||||||
'mentions' => Type::listOf($this->mention)
|
'mentions' => Type::listOf($this->mention),
|
||||||
]
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->postStoryMutationInput = new InputObjectType([
|
||||||
|
'name' => 'PostStoryMutationInput',
|
||||||
|
'fields' => [
|
||||||
|
'title' => Type::string(),
|
||||||
|
'body' => Type::string(),
|
||||||
|
'author' => Type::id(),
|
||||||
|
'category' => Type::id(),
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->mutation = new ObjectType([
|
$this->mutation = new ObjectType([
|
||||||
@ -234,28 +218,20 @@ class ExtractTypesTest extends TestCase
|
|||||||
'type' => $this->postStoryMutation = new ObjectType([
|
'type' => $this->postStoryMutation = new ObjectType([
|
||||||
'name' => 'PostStoryMutation',
|
'name' => 'PostStoryMutation',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'story' => $this->blogStory
|
'story' => $this->blogStory,
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'args' => [
|
'args' => [
|
||||||
'input' => Type::nonNull($this->postStoryMutationInput = new InputObjectType([
|
'input' => Type::nonNull($this->postStoryMutationInput),
|
||||||
'name' => 'PostStoryMutationInput',
|
'clientRequestId' => Type::string(),
|
||||||
'fields' => [
|
],
|
||||||
'title' => Type::string(),
|
|
||||||
'body' => Type::string(),
|
|
||||||
'author' => Type::id(),
|
|
||||||
'category' => Type::id()
|
|
||||||
]
|
|
||||||
])),
|
|
||||||
'clientRequestId' => Type::string()
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'postComment' => [
|
'postComment' => [
|
||||||
'type' => $this->postCommentMutation = new ObjectType([
|
'type' => $this->postCommentMutation = new ObjectType([
|
||||||
'name' => 'PostCommentMutation',
|
'name' => 'PostCommentMutation',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'comment' => $this->comment
|
'comment' => $this->comment,
|
||||||
]
|
],
|
||||||
]),
|
]),
|
||||||
'args' => [
|
'args' => [
|
||||||
'input' => Type::nonNull($this->postCommentMutationInput = new InputObjectType([
|
'input' => Type::nonNull($this->postCommentMutationInput = new InputObjectType([
|
||||||
@ -264,13 +240,13 @@ class ExtractTypesTest extends TestCase
|
|||||||
'text' => Type::nonNull(Type::string()),
|
'text' => Type::nonNull(Type::string()),
|
||||||
'author' => Type::nonNull(Type::id()),
|
'author' => Type::nonNull(Type::id()),
|
||||||
'content' => Type::id(),
|
'content' => Type::id(),
|
||||||
'parent' => Type::id()
|
'parent' => Type::id(),
|
||||||
]
|
],
|
||||||
])),
|
])),
|
||||||
'clientRequestId' => Type::string()
|
'clientRequestId' => Type::string(),
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,15 +293,15 @@ class ExtractTypesTest extends TestCase
|
|||||||
{
|
{
|
||||||
$otherUserType = new ObjectType([
|
$otherUserType = new ObjectType([
|
||||||
'name' => 'User',
|
'name' => 'User',
|
||||||
'fields' => ['a' => Type::string()]
|
'fields' => ['a' => Type::string()],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$queryType = new ObjectType([
|
$queryType = new ObjectType([
|
||||||
'name' => 'Test',
|
'name' => 'Test',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'otherUser' => $otherUserType,
|
'otherUser' => $otherUserType,
|
||||||
'user' => $this->user
|
'user' => $this->user,
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->expectException(InvariantViolation::class);
|
$this->expectException(InvariantViolation::class);
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Utils;
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Language\SourceLocation;
|
use GraphQL\Language\SourceLocation;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Utils\Utils;
|
|
||||||
use GraphQL\Validator\DocumentValidator;
|
use GraphQL\Validator\DocumentValidator;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class IsValidLiteralValueTest extends TestCase
|
class IsValidLiteralValueTest extends TestCase
|
||||||
{
|
{
|
||||||
// DESCRIBE: isValidLiteralValue
|
// DESCRIBE: isValidLiteralValue
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Returns no errors for a valid value')
|
* @see it('Returns no errors for a valid value')
|
||||||
*/
|
*/
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Utils;
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
|
|
||||||
use GraphQL\Utils\Utils;
|
|
||||||
use GraphQL\Utils\MixedStore;
|
use GraphQL\Utils\MixedStore;
|
||||||
|
use GraphQL\Utils\Utils;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class MixedStoreTest extends TestCase
|
class MixedStoreTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/** @var MixedStore */
|
||||||
* @var MixedStore
|
|
||||||
*/
|
|
||||||
private $mixedStore;
|
private $mixedStore;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -18,6 +18,13 @@ class MixedStoreTest extends TestCase
|
|||||||
$this->mixedStore = new MixedStore();
|
$this->mixedStore = new MixedStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAcceptsNullKeys() : void
|
||||||
|
{
|
||||||
|
foreach ($this->getPossibleValues() as $value) {
|
||||||
|
$this->assertAcceptsKeyValue(null, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getPossibleValues()
|
public function getPossibleValues()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@ -30,16 +37,38 @@ class MixedStoreTest extends TestCase
|
|||||||
'a',
|
'a',
|
||||||
[],
|
[],
|
||||||
new \stdClass(),
|
new \stdClass(),
|
||||||
function() {},
|
function () {
|
||||||
new MixedStore()
|
},
|
||||||
|
new MixedStore(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAcceptsNullKeys() : void
|
private function assertAcceptsKeyValue($key, $value)
|
||||||
{
|
{
|
||||||
foreach ($this->getPossibleValues() as $value) {
|
$err = 'Failed assertion that MixedStore accepts key ' .
|
||||||
$this->assertAcceptsKeyValue(null, $value);
|
Utils::printSafe($key) . ' with value ' . Utils::printSafe($value);
|
||||||
|
|
||||||
|
$this->assertFalse($this->mixedStore->offsetExists($key), $err);
|
||||||
|
$this->mixedStore->offsetSet($key, $value);
|
||||||
|
$this->assertTrue($this->mixedStore->offsetExists($key), $err);
|
||||||
|
$this->assertSame($value, $this->mixedStore->offsetGet($key), $err);
|
||||||
|
$this->mixedStore->offsetUnset($key);
|
||||||
|
$this->assertFalse($this->mixedStore->offsetExists($key), $err);
|
||||||
|
$this->assertProvidesArrayAccess($key, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function assertProvidesArrayAccess($key, $value)
|
||||||
|
{
|
||||||
|
$err = 'Failed assertion that MixedStore provides array access for key ' .
|
||||||
|
Utils::printSafe($key) . ' with value ' . Utils::printSafe($value);
|
||||||
|
|
||||||
|
$this->assertFalse(isset($this->mixedStore[$key]), $err);
|
||||||
|
$this->mixedStore[$key] = $value;
|
||||||
|
$this->assertTrue(isset($this->mixedStore[$key]), $err);
|
||||||
|
$this->assertEquals(! empty($value), ! empty($this->mixedStore[$key]), $err);
|
||||||
|
$this->assertSame($value, $this->mixedStore[$key], $err);
|
||||||
|
unset($this->mixedStore[$key]);
|
||||||
|
$this->assertFalse(isset($this->mixedStore[$key]), $err);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAcceptsBoolKeys() : void
|
public function testAcceptsBoolKeys() : void
|
||||||
@ -93,35 +122,11 @@ class MixedStoreTest extends TestCase
|
|||||||
foreach ($this->getPossibleValues() as $value) {
|
foreach ($this->getPossibleValues() as $value) {
|
||||||
$this->assertAcceptsKeyValue(new \stdClass(), $value);
|
$this->assertAcceptsKeyValue(new \stdClass(), $value);
|
||||||
$this->assertAcceptsKeyValue(new MixedStore(), $value);
|
$this->assertAcceptsKeyValue(new MixedStore(), $value);
|
||||||
$this->assertAcceptsKeyValue(function() {}, $value);
|
$this->assertAcceptsKeyValue(
|
||||||
|
function () {
|
||||||
|
},
|
||||||
|
$value
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function assertAcceptsKeyValue($key, $value)
|
|
||||||
{
|
|
||||||
$err = 'Failed assertion that MixedStore accepts key ' .
|
|
||||||
Utils::printSafe($key) . ' with value ' . Utils::printSafe($value);
|
|
||||||
|
|
||||||
$this->assertFalse($this->mixedStore->offsetExists($key), $err);
|
|
||||||
$this->mixedStore->offsetSet($key, $value);
|
|
||||||
$this->assertTrue($this->mixedStore->offsetExists($key), $err);
|
|
||||||
$this->assertSame($value, $this->mixedStore->offsetGet($key), $err);
|
|
||||||
$this->mixedStore->offsetUnset($key);
|
|
||||||
$this->assertFalse($this->mixedStore->offsetExists($key), $err);
|
|
||||||
$this->assertProvidesArrayAccess($key, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function assertProvidesArrayAccess($key, $value)
|
|
||||||
{
|
|
||||||
$err = 'Failed assertion that MixedStore provides array access for key ' .
|
|
||||||
Utils::printSafe($key) . ' with value ' . Utils::printSafe($value);
|
|
||||||
|
|
||||||
$this->assertFalse(isset($this->mixedStore[$key]), $err);
|
|
||||||
$this->mixedStore[$key] = $value;
|
|
||||||
$this->assertTrue(isset($this->mixedStore[$key]), $err);
|
|
||||||
$this->assertEquals(!empty($value), !empty($this->mixedStore[$key]), $err);
|
|
||||||
$this->assertSame($value, $this->mixedStore[$key], $err);
|
|
||||||
unset($this->mixedStore[$key]);
|
|
||||||
$this->assertFalse(isset($this->mixedStore[$key]), $err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Utils;
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
use GraphQL\Executor\Values;
|
|
||||||
use GraphQL\Type\Definition\Type;
|
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
use GraphQL\Utils\Value;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class QuotedOrListTest extends TestCase
|
class QuotedOrListTest extends TestCase
|
||||||
{
|
{
|
||||||
// DESCRIBE: quotedOrList
|
// DESCRIBE: quotedOrList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Does not accept an empty list')
|
* @see it('Does not accept an empty list')
|
||||||
*/
|
*/
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Utils;
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
use GraphQL\Language\DirectiveLocation;
|
use GraphQL\Language\DirectiveLocation;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
use GraphQL\Type\Definition\CustomScalarType;
|
use GraphQL\Type\Definition\CustomScalarType;
|
||||||
use GraphQL\Type\Definition\Directive;
|
use GraphQL\Type\Definition\Directive;
|
||||||
|
use GraphQL\Type\Definition\EnumType;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\EnumType;
|
|
||||||
use GraphQL\Type\Definition\UnionType;
|
use GraphQL\Type\Definition\UnionType;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
use GraphQL\Utils\BuildSchema;
|
use GraphQL\Utils\BuildSchema;
|
||||||
use GraphQL\Utils\SchemaPrinter;
|
use GraphQL\Utils\SchemaPrinter;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
@ -19,37 +22,40 @@ class SchemaPrinterTest extends TestCase
|
|||||||
{
|
{
|
||||||
// Describe: Type System Printer
|
// Describe: Type System Printer
|
||||||
|
|
||||||
private function printForTest($schema)
|
|
||||||
{
|
|
||||||
$schemaText = SchemaPrinter::doPrint($schema);
|
|
||||||
$this->assertEquals($schemaText, SchemaPrinter::doPrint(BuildSchema::build($schemaText)));
|
|
||||||
return "\n" . $schemaText;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function printSingleFieldSchema($fieldConfig)
|
|
||||||
{
|
|
||||||
$query = new ObjectType([
|
|
||||||
'name' => 'Query',
|
|
||||||
'fields' => [
|
|
||||||
'singleField' => $fieldConfig
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
return $this->printForTest(new Schema(['query' => $query]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Prints String Field')
|
* @see it('Prints String Field')
|
||||||
*/
|
*/
|
||||||
public function testPrintsStringField() : void
|
public function testPrintsStringField() : void
|
||||||
{
|
{
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
'type' => Type::string()
|
'type' => Type::string(),
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField: String
|
singleField: String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function printSingleFieldSchema($fieldConfig)
|
||||||
|
{
|
||||||
|
$query = new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => ['singleField' => $fieldConfig],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->printForTest(new Schema(['query' => $query]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function printForTest($schema)
|
||||||
|
{
|
||||||
|
$schemaText = SchemaPrinter::doPrint($schema);
|
||||||
|
$this->assertEquals($schemaText, SchemaPrinter::doPrint(BuildSchema::build($schemaText)));
|
||||||
|
|
||||||
|
return "\n" . $schemaText;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,13 +64,16 @@ type Query {
|
|||||||
public function testPrintArrayStringField() : void
|
public function testPrintArrayStringField() : void
|
||||||
{
|
{
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
'type' => Type::listOf(Type::string())
|
'type' => Type::listOf(Type::string()),
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField: [String]
|
singleField: [String]
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,13 +82,16 @@ type Query {
|
|||||||
public function testPrintNonNullStringField() : void
|
public function testPrintNonNullStringField() : void
|
||||||
{
|
{
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
'type' => Type::nonNull(Type::string())
|
'type' => Type::nonNull(Type::string()),
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField: String!
|
singleField: String!
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,13 +100,16 @@ type Query {
|
|||||||
public function testPrintNonNullArrayStringField() : void
|
public function testPrintNonNullArrayStringField() : void
|
||||||
{
|
{
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
'type' => Type::nonNull(Type::listOf(Type::string()))
|
'type' => Type::nonNull(Type::listOf(Type::string())),
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField: [String]!
|
singleField: [String]!
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,13 +118,16 @@ type Query {
|
|||||||
public function testPrintArrayNonNullStringField() : void
|
public function testPrintArrayNonNullStringField() : void
|
||||||
{
|
{
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
'type' => Type::listOf(Type::nonNull(Type::string()))
|
'type' => Type::listOf(Type::nonNull(Type::string())),
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField: [String!]
|
singleField: [String!]
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,13 +136,16 @@ type Query {
|
|||||||
public function testPrintNonNullArrayNonNullStringField() : void
|
public function testPrintNonNullArrayNonNullStringField() : void
|
||||||
{
|
{
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
'type' => Type::nonNull(Type::listOf(Type::nonNull(Type::string())))
|
'type' => Type::nonNull(Type::listOf(Type::nonNull(Type::string()))),
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField: [String!]!
|
singleField: [String!]!
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -134,17 +155,18 @@ type Query {
|
|||||||
{
|
{
|
||||||
$fooType = new ObjectType([
|
$fooType = new ObjectType([
|
||||||
'name' => 'Foo',
|
'name' => 'Foo',
|
||||||
'fields' => ['str' => ['type' => Type::string()]]
|
'fields' => ['str' => ['type' => Type::string()]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$root = new ObjectType([
|
$root = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => ['foo' => ['type' => $fooType]]
|
'fields' => ['foo' => ['type' => $fooType]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $root]);
|
$schema = new Schema(['query' => $root]);
|
||||||
$output = $this->printForTest($schema);
|
$output = $this->printForTest($schema);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Foo {
|
type Foo {
|
||||||
str: String
|
str: String
|
||||||
}
|
}
|
||||||
@ -152,7 +174,9 @@ type Foo {
|
|||||||
type Query {
|
type Query {
|
||||||
foo: Foo
|
foo: Foo
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,13 +186,16 @@ type Query {
|
|||||||
{
|
{
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'args' => ['argOne' => ['type' => Type::int()]]
|
'args' => ['argOne' => ['type' => Type::int()]],
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField(argOne: Int): String
|
singleField(argOne: Int): String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,13 +205,16 @@ type Query {
|
|||||||
{
|
{
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'args' => ['argOne' => ['type' => Type::int(), 'defaultValue' => 2]]
|
'args' => ['argOne' => ['type' => Type::int(), 'defaultValue' => 2]],
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField(argOne: Int = 2): String
|
singleField(argOne: Int = 2): String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,11 +226,14 @@ type Query {
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'args' => ['argOne' => ['type' => Type::string(), 'defaultValue' => "tes\t de\fault"]],
|
'args' => ['argOne' => ['type' => Type::string(), 'defaultValue' => "tes\t de\fault"]],
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField(argOne: String = "tes\t de\fault"): String
|
singleField(argOne: String = "tes\t de\fault"): String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,13 +243,16 @@ type Query {
|
|||||||
{
|
{
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'args' => ['argOne' => ['type' => Type::int(), 'defaultValue' => null]]
|
'args' => ['argOne' => ['type' => Type::int(), 'defaultValue' => null]],
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField(argOne: Int = null): String
|
singleField(argOne: Int = null): String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -226,13 +262,16 @@ type Query {
|
|||||||
{
|
{
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'args' => ['argOne' => ['type' => Type::nonNull(Type::int())]]
|
'args' => ['argOne' => ['type' => Type::nonNull(Type::int())]],
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField(argOne: Int!): String
|
singleField(argOne: Int!): String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -244,14 +283,17 @@ type Query {
|
|||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'args' => [
|
'args' => [
|
||||||
'argOne' => ['type' => Type::int()],
|
'argOne' => ['type' => Type::int()],
|
||||||
'argTwo' => ['type' => Type::string()]
|
'argTwo' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField(argOne: Int, argTwo: String): String
|
singleField(argOne: Int, argTwo: String): String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -264,14 +306,17 @@ type Query {
|
|||||||
'args' => [
|
'args' => [
|
||||||
'argOne' => ['type' => Type::int(), 'defaultValue' => 1],
|
'argOne' => ['type' => Type::int(), 'defaultValue' => 1],
|
||||||
'argTwo' => ['type' => Type::string()],
|
'argTwo' => ['type' => Type::string()],
|
||||||
'argThree' => ['type' => Type::boolean()]
|
'argThree' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String
|
singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -284,14 +329,17 @@ type Query {
|
|||||||
'args' => [
|
'args' => [
|
||||||
'argOne' => ['type' => Type::int()],
|
'argOne' => ['type' => Type::int()],
|
||||||
'argTwo' => ['type' => Type::string(), 'defaultValue' => 'foo'],
|
'argTwo' => ['type' => Type::string(), 'defaultValue' => 'foo'],
|
||||||
'argThree' => ['type' => Type::boolean()]
|
'argThree' => ['type' => Type::boolean()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField(argOne: Int, argTwo: String = "foo", argThree: Boolean): String
|
singleField(argOne: Int, argTwo: String = "foo", argThree: Boolean): String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -304,14 +352,17 @@ type Query {
|
|||||||
'args' => [
|
'args' => [
|
||||||
'argOne' => ['type' => Type::int()],
|
'argOne' => ['type' => Type::int()],
|
||||||
'argTwo' => ['type' => Type::string()],
|
'argTwo' => ['type' => Type::string()],
|
||||||
'argThree' => ['type' => Type::boolean(), 'defaultValue' => false]
|
'argThree' => ['type' => Type::boolean(), 'defaultValue' => false],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String
|
singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -324,9 +375,7 @@ type Query {
|
|||||||
'fields' => ['bar' => ['type' => Type::string()]],
|
'fields' => ['bar' => ['type' => Type::string()]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema(['query' => $customQueryType]);
|
||||||
'query' => $customQueryType,
|
|
||||||
]);
|
|
||||||
$output = $this->printForTest($schema);
|
$output = $this->printForTest($schema);
|
||||||
$expected = '
|
$expected = '
|
||||||
schema {
|
schema {
|
||||||
@ -347,26 +396,27 @@ type CustomQueryType {
|
|||||||
{
|
{
|
||||||
$fooType = new InterfaceType([
|
$fooType = new InterfaceType([
|
||||||
'name' => 'Foo',
|
'name' => 'Foo',
|
||||||
'fields' => ['str' => ['type' => Type::string()]]
|
'fields' => ['str' => ['type' => Type::string()]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$barType = new ObjectType([
|
$barType = new ObjectType([
|
||||||
'name' => 'Bar',
|
'name' => 'Bar',
|
||||||
'fields' => ['str' => ['type' => Type::string()]],
|
'fields' => ['str' => ['type' => Type::string()]],
|
||||||
'interfaces' => [$fooType]
|
'interfaces' => [$fooType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => ['bar' => ['type' => $barType]]
|
'fields' => ['bar' => ['type' => $barType]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'types' => [$barType]
|
'types' => [$barType],
|
||||||
]);
|
]);
|
||||||
$output = $this->printForTest($schema);
|
$output = $this->printForTest($schema);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Bar implements Foo {
|
type Bar implements Foo {
|
||||||
str: String
|
str: String
|
||||||
}
|
}
|
||||||
@ -378,7 +428,9 @@ interface Foo {
|
|||||||
type Query {
|
type Query {
|
||||||
bar: Bar
|
bar: Bar
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -388,34 +440,35 @@ type Query {
|
|||||||
{
|
{
|
||||||
$fooType = new InterfaceType([
|
$fooType = new InterfaceType([
|
||||||
'name' => 'Foo',
|
'name' => 'Foo',
|
||||||
'fields' => ['str' => ['type' => Type::string()]]
|
'fields' => ['str' => ['type' => Type::string()]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$baazType = new InterfaceType([
|
$baazType = new InterfaceType([
|
||||||
'name' => 'Baaz',
|
'name' => 'Baaz',
|
||||||
'fields' => ['int' => ['type' => Type::int()]]
|
'fields' => ['int' => ['type' => Type::int()]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$barType = new ObjectType([
|
$barType = new ObjectType([
|
||||||
'name' => 'Bar',
|
'name' => 'Bar',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'str' => ['type' => Type::string()],
|
'str' => ['type' => Type::string()],
|
||||||
'int' => ['type' => Type::int()]
|
'int' => ['type' => Type::int()],
|
||||||
],
|
],
|
||||||
'interfaces' => [$fooType, $baazType]
|
'interfaces' => [$fooType, $baazType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => ['bar' => ['type' => $barType]]
|
'fields' => ['bar' => ['type' => $barType]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'types' => [$barType]
|
'types' => [$barType],
|
||||||
]);
|
]);
|
||||||
$output = $this->printForTest($schema);
|
$output = $this->printForTest($schema);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
interface Baaz {
|
interface Baaz {
|
||||||
int: Int
|
int: Int
|
||||||
}
|
}
|
||||||
@ -432,7 +485,9 @@ interface Foo {
|
|||||||
type Query {
|
type Query {
|
||||||
bar: Bar
|
bar: Bar
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -442,35 +497,36 @@ type Query {
|
|||||||
{
|
{
|
||||||
$fooType = new ObjectType([
|
$fooType = new ObjectType([
|
||||||
'name' => 'Foo',
|
'name' => 'Foo',
|
||||||
'fields' => ['bool' => ['type' => Type::boolean()]]
|
'fields' => ['bool' => ['type' => Type::boolean()]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$barType = new ObjectType([
|
$barType = new ObjectType([
|
||||||
'name' => 'Bar',
|
'name' => 'Bar',
|
||||||
'fields' => ['str' => ['type' => Type::string()]]
|
'fields' => ['str' => ['type' => Type::string()]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$singleUnion = new UnionType([
|
$singleUnion = new UnionType([
|
||||||
'name' => 'SingleUnion',
|
'name' => 'SingleUnion',
|
||||||
'types' => [$fooType]
|
'types' => [$fooType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$multipleUnion = new UnionType([
|
$multipleUnion = new UnionType([
|
||||||
'name' => 'MultipleUnion',
|
'name' => 'MultipleUnion',
|
||||||
'types' => [$fooType, $barType]
|
'types' => [$fooType, $barType],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'single' => ['type' => $singleUnion],
|
'single' => ['type' => $singleUnion],
|
||||||
'multiple' => ['type' => $multipleUnion]
|
'multiple' => ['type' => $multipleUnion],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $query]);
|
$schema = new Schema(['query' => $query]);
|
||||||
$output = $this->printForTest($schema);
|
$output = $this->printForTest($schema);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Bar {
|
type Bar {
|
||||||
str: String
|
str: String
|
||||||
}
|
}
|
||||||
@ -487,7 +543,9 @@ type Query {
|
|||||||
}
|
}
|
||||||
|
|
||||||
union SingleUnion = Foo
|
union SingleUnion = Foo
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -497,7 +555,7 @@ union SingleUnion = Foo
|
|||||||
{
|
{
|
||||||
$inputType = new InputObjectType([
|
$inputType = new InputObjectType([
|
||||||
'name' => 'InputType',
|
'name' => 'InputType',
|
||||||
'fields' => ['int' => ['type' => Type::int()]]
|
'fields' => ['int' => ['type' => Type::int()]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
@ -505,14 +563,15 @@ union SingleUnion = Foo
|
|||||||
'fields' => [
|
'fields' => [
|
||||||
'str' => [
|
'str' => [
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'args' => ['argOne' => ['type' => $inputType]]
|
'args' => ['argOne' => ['type' => $inputType]],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $query]);
|
$schema = new Schema(['query' => $query]);
|
||||||
$output = $this->printForTest($schema);
|
$output = $this->printForTest($schema);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
input InputType {
|
input InputType {
|
||||||
int: Int
|
int: Int
|
||||||
}
|
}
|
||||||
@ -520,7 +579,9 @@ input InputType {
|
|||||||
type Query {
|
type Query {
|
||||||
str(argOne: InputType): String
|
str(argOne: InputType): String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -530,27 +591,30 @@ type Query {
|
|||||||
{
|
{
|
||||||
$oddType = new CustomScalarType([
|
$oddType = new CustomScalarType([
|
||||||
'name' => 'Odd',
|
'name' => 'Odd',
|
||||||
'serialize' => function($value) {
|
'serialize' => function ($value) {
|
||||||
return $value % 2 === 1 ? $value : null;
|
return $value % 2 === 1 ? $value : null;
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'odd' => ['type' => $oddType]
|
'odd' => ['type' => $oddType],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $query]);
|
$schema = new Schema(['query' => $query]);
|
||||||
$output = $this->printForTest($schema);
|
$output = $this->printForTest($schema);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
scalar Odd
|
scalar Odd
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
odd: Odd
|
odd: Odd
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -563,20 +627,21 @@ type Query {
|
|||||||
'values' => [
|
'values' => [
|
||||||
'RED' => ['value' => 0],
|
'RED' => ['value' => 0],
|
||||||
'GREEN' => ['value' => 1],
|
'GREEN' => ['value' => 1],
|
||||||
'BLUE' => ['value' => 2]
|
'BLUE' => ['value' => 2],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'rgb' => ['type' => $RGBType]
|
'rgb' => ['type' => $RGBType],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $query]);
|
$schema = new Schema(['query' => $query]);
|
||||||
$output = $this->printForTest($schema);
|
$output = $this->printForTest($schema);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
rgb: RGB
|
rgb: RGB
|
||||||
}
|
}
|
||||||
@ -586,7 +651,9 @@ enum RGB {
|
|||||||
GREEN
|
GREEN
|
||||||
BLUE
|
BLUE
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -598,14 +665,14 @@ enum RGB {
|
|||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'field' => ['type' => Type::string()],
|
'field' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$customDirectives = new Directive([
|
$customDirectives = new Directive([
|
||||||
'name' => 'customDirective',
|
'name' => 'customDirective',
|
||||||
'locations' => [
|
'locations' => [
|
||||||
DirectiveLocation::FIELD
|
DirectiveLocation::FIELD,
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -614,13 +681,16 @@ enum RGB {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$output = $this->printForTest($schema);
|
$output = $this->printForTest($schema);
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
directive @customDirective on FIELD
|
directive @customDirective on FIELD
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
field: String
|
field: String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -630,16 +700,19 @@ type Query {
|
|||||||
{
|
{
|
||||||
$description = 'This field is awesome';
|
$description = 'This field is awesome';
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
"type" => Type::string(),
|
'type' => Type::string(),
|
||||||
"description" => $description
|
'description' => $description,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
"""This field is awesome"""
|
"""This field is awesome"""
|
||||||
singleField: String
|
singleField: String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
|
|
||||||
$recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
|
$recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
|
||||||
$recreatedField = $recreatedRoot->getFields()['singleField'];
|
$recreatedField = $recreatedRoot->getFields()['singleField'];
|
||||||
@ -653,18 +726,21 @@ type Query {
|
|||||||
{
|
{
|
||||||
$description = 'This field is "awesome"';
|
$description = 'This field is "awesome"';
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
"type" => Type::string(),
|
'type' => Type::string(),
|
||||||
"description" => $description
|
'description' => $description,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
"""
|
"""
|
||||||
This field is "awesome"
|
This field is "awesome"
|
||||||
"""
|
"""
|
||||||
singleField: String
|
singleField: String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
|
|
||||||
$recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
|
$recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
|
||||||
$recreatedField = $recreatedRoot->getFields()['singleField'];
|
$recreatedField = $recreatedRoot->getFields()['singleField'];
|
||||||
@ -678,17 +754,20 @@ type Query {
|
|||||||
{
|
{
|
||||||
$description = ' This field is "awesome"';
|
$description = ' This field is "awesome"';
|
||||||
$output = $this->printSingleFieldSchema([
|
$output = $this->printSingleFieldSchema([
|
||||||
"type" => Type::string(),
|
'type' => Type::string(),
|
||||||
"description" => $description
|
'description' => $description,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals('
|
$this->assertEquals(
|
||||||
|
'
|
||||||
type Query {
|
type Query {
|
||||||
""" This field is "awesome"
|
""" This field is "awesome"
|
||||||
"""
|
"""
|
||||||
singleField: String
|
singleField: String
|
||||||
}
|
}
|
||||||
', $output);
|
',
|
||||||
|
$output
|
||||||
|
);
|
||||||
|
|
||||||
$recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
|
$recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
|
||||||
$recreatedField = $recreatedRoot->getFields()['singleField'];
|
$recreatedField = $recreatedRoot->getFields()['singleField'];
|
||||||
@ -703,8 +782,8 @@ type Query {
|
|||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'onlyField' => ['type' => Type::string()]
|
'onlyField' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $query]);
|
$schema = new Schema(['query' => $query]);
|
||||||
@ -948,14 +1027,15 @@ EOT;
|
|||||||
$query = new ObjectType([
|
$query = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'onlyField' => ['type' => Type::string()]
|
'onlyField' => ['type' => Type::string()],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $query]);
|
$schema = new Schema(['query' => $query]);
|
||||||
$output = SchemaPrinter::printIntrosepctionSchema($schema, [
|
$output = SchemaPrinter::printIntrosepctionSchema(
|
||||||
'commentDescriptions' => true
|
$schema,
|
||||||
]);
|
['commentDescriptions' => true]
|
||||||
|
);
|
||||||
$introspectionSchema = <<<'EOT'
|
$introspectionSchema = <<<'EOT'
|
||||||
# Directs the executor to include this field or fragment only when the `if` argument is true.
|
# Directs the executor to include this field or fragment only when the `if` argument is true.
|
||||||
directive @include(
|
directive @include(
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GraphQL\Tests\Utils;
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
use GraphQL\Executor\Values;
|
|
||||||
use GraphQL\Type\Definition\Type;
|
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
use GraphQL\Utils\Value;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class SuggestionListTest extends TestCase
|
class SuggestionListTest extends TestCase
|
||||||
{
|
{
|
||||||
// DESCRIBE: suggestionList
|
// DESCRIBE: suggestionList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see it('Returns results when input is empty')
|
* @see it('Returns results when input is empty')
|
||||||
*/
|
*/
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user