mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-22 12:56:05 +03:00
Merge branch 'master' into no-parsing
This commit is contained in:
commit
918bbff2bd
10
.gitattributes
vendored
10
.gitattributes
vendored
@ -1,2 +1,12 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text eol=lf
|
||||
/benchmarks export-ignore
|
||||
/tests export-ignore
|
||||
/tools export-ignore
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
.travis.yml export-ignore
|
||||
CONTRIBUTING.md export-ignore
|
||||
mkdocs.yml export-ignore
|
||||
phpbench.json export-ignore
|
||||
phpunit.xml.dist export-ignore
|
||||
|
36
UPGRADE.md
36
UPGRADE.md
@ -1,3 +1,39 @@
|
||||
## Upgrade v0.10.x > dev-master
|
||||
|
||||
### Possibly Breaking: AST to array serialization excludes nulls
|
||||
Most users won't be affected. It *may* affect you only if you do your own manipulations
|
||||
with exported AST.
|
||||
|
||||
Example of json-serialized AST before the change:
|
||||
```json
|
||||
{
|
||||
"kind": "Field",
|
||||
"loc": null,
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"loc": null,
|
||||
"value": "id"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
}
|
||||
```
|
||||
After the change:
|
||||
```json
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "id"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": []
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Upgrade v0.8.x, v0.9.x > v0.10.x
|
||||
|
||||
### Breaking: changed minimum PHP version from 5.4 to 5.5
|
||||
|
@ -5,6 +5,7 @@
|
||||
- [Symfony Bundle](https://github.com/overblog/GraphQLBundle) by Overblog
|
||||
- Define types with Doctrine ORM annotations ([for PHP7.1](https://github.com/Ecodev/graphql-doctrine), for [earlier PHP versions](https://github.com/rahuljayaraman/doctrine-graphql))
|
||||
- Out of the box integration with any PSR-7 compatible framework (like [Slim](http://slimframework.com) or [Zend Expressive](http://zendframework.github.io/zend-expressive/)) via [Standard Server](executing-queries.md/#using-server)
|
||||
- [PSR 15 compliant middleware](https://github.com/phps-cans/psr7-middleware-graphql) for the Standard Server (experimental)
|
||||
|
||||
# Tools
|
||||
- [GraphiQL](https://github.com/graphql/graphiql) - An in-browser IDE for exploring GraphQL
|
||||
|
@ -99,10 +99,12 @@ abstract class Node
|
||||
} else {
|
||||
$tmp = (array) $this;
|
||||
|
||||
$tmp['loc'] = [
|
||||
'start' => $this->loc->start,
|
||||
'end' => $this->loc->end
|
||||
];
|
||||
if ($this->loc) {
|
||||
$tmp['loc'] = [
|
||||
'start' => $this->loc->start,
|
||||
'end' => $this->loc->end
|
||||
];
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
@ -116,16 +118,22 @@ abstract class Node
|
||||
{
|
||||
$result = [
|
||||
'kind' => $node->kind,
|
||||
'loc' => [
|
||||
];
|
||||
|
||||
if ($node->loc) {
|
||||
$result['loc'] = [
|
||||
'start' => $node->loc->start,
|
||||
'end' => $node->loc->end
|
||||
]
|
||||
];
|
||||
];
|
||||
}
|
||||
|
||||
foreach (get_object_vars($node) as $prop => $propValue) {
|
||||
if (isset($result[$prop]))
|
||||
continue;
|
||||
|
||||
if ($propValue === null)
|
||||
continue;
|
||||
|
||||
if (is_array($propValue) || $propValue instanceof NodeList) {
|
||||
$tmp = [];
|
||||
foreach ($propValue as $tmp1) {
|
||||
|
@ -3,6 +3,7 @@ namespace GraphQL\Language\AST;
|
||||
|
||||
/**
|
||||
export type ValueNode = VariableNode
|
||||
| NullValueNode
|
||||
| IntValueNode
|
||||
| FloatValueNode
|
||||
| StringValueNode
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?php
|
||||
namespace GraphQL\Validator\Rules;
|
||||
|
||||
use GraphQL\Error\Error;
|
||||
use GraphQL\Validator\ValidationContext;
|
||||
|
||||
abstract class AbstractValidationRule
|
||||
@ -19,8 +18,11 @@ abstract class AbstractValidationRule
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns structure suitable for GraphQL\Language\Visitor
|
||||
*
|
||||
* @see \GraphQL\Language\Visitor
|
||||
* @param ValidationContext $context
|
||||
* @return Error[]
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getVisitor(ValidationContext $context);
|
||||
}
|
||||
|
@ -40,12 +40,8 @@ class SyncPromiseAdapterTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Promise', $result);
|
||||
$this->assertInstanceOf('GraphQL\Executor\Promise\Adapter\SyncPromise', $result->adoptedPromise);
|
||||
|
||||
try {
|
||||
$this->promises->convertThenable('');
|
||||
$this->fail('Expected exception no thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Expected instance of GraphQL\Deferred, got (empty string)', $e->getMessage());
|
||||
}
|
||||
$this->setExpectedException(InvariantViolation::class, 'Expected instance of GraphQL\Deferred, got (empty string)');
|
||||
$this->promises->convertThenable('');
|
||||
}
|
||||
|
||||
public function testThen()
|
||||
|
@ -33,7 +33,7 @@ class SyncPromiseTest extends \PHPUnit_Framework_TestCase
|
||||
/**
|
||||
* @dataProvider getFulfilledPromiseResolveData
|
||||
*/
|
||||
public function testFulfilledPromise(
|
||||
public function testFulfilledPromiseCannotChangeValue(
|
||||
$resolvedValue,
|
||||
$onFulfilled,
|
||||
$expectedNextValue,
|
||||
@ -47,19 +47,47 @@ class SyncPromiseTest extends \PHPUnit_Framework_TestCase
|
||||
$promise->resolve($resolvedValue);
|
||||
$this->assertEquals(SyncPromise::FULFILLED, $promise->state);
|
||||
|
||||
try {
|
||||
$promise->resolve($resolvedValue . '-other-value');
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('Cannot change value of fulfilled promise', $e->getMessage());
|
||||
}
|
||||
$this->setExpectedException(\Exception::class, 'Cannot change value of fulfilled promise');
|
||||
$promise->resolve($resolvedValue . '-other-value');
|
||||
}
|
||||
|
||||
try {
|
||||
$promise->reject(new \Exception('anything'));
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('Cannot reject fulfilled promise', $e->getMessage());
|
||||
}
|
||||
/**
|
||||
* @dataProvider getFulfilledPromiseResolveData
|
||||
*/
|
||||
public function testFulfilledPromiseCannotBeRejected(
|
||||
$resolvedValue,
|
||||
$onFulfilled,
|
||||
$expectedNextValue,
|
||||
$expectedNextReason,
|
||||
$expectedNextState
|
||||
)
|
||||
{
|
||||
$promise = new SyncPromise();
|
||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||
|
||||
$promise->resolve($resolvedValue);
|
||||
$this->assertEquals(SyncPromise::FULFILLED, $promise->state);
|
||||
|
||||
$this->setExpectedException(\Exception::class, 'Cannot reject fulfilled promise');
|
||||
$promise->reject(new \Exception('anything'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getFulfilledPromiseResolveData
|
||||
*/
|
||||
public function testFulfilledPromise(
|
||||
$resolvedValue,
|
||||
$onFulfilled,
|
||||
$expectedNextValue,
|
||||
$expectedNextReason,
|
||||
$expectedNextState
|
||||
)
|
||||
{
|
||||
$promise = new SyncPromise();
|
||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||
|
||||
$promise->resolve($resolvedValue);
|
||||
$this->assertEquals(SyncPromise::FULFILLED, $promise->state);
|
||||
|
||||
$nextPromise = $promise->then(null, function() {});
|
||||
$this->assertSame($promise, $nextPromise);
|
||||
@ -117,6 +145,49 @@ class SyncPromiseTest extends \PHPUnit_Framework_TestCase
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getRejectedPromiseData
|
||||
*/
|
||||
public function testRejectedPromiseCannotChangeReason(
|
||||
$rejectedReason,
|
||||
$onRejected,
|
||||
$expectedNextValue,
|
||||
$expectedNextReason,
|
||||
$expectedNextState
|
||||
)
|
||||
{
|
||||
$promise = new SyncPromise();
|
||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||
|
||||
$promise->reject($rejectedReason);
|
||||
$this->assertEquals(SyncPromise::REJECTED, $promise->state);
|
||||
|
||||
$this->setExpectedException(\Exception::class, 'Cannot change rejection reason');
|
||||
$promise->reject(new \Exception('other-reason'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getRejectedPromiseData
|
||||
*/
|
||||
public function testRejectedPromiseCannotBeResolved(
|
||||
$rejectedReason,
|
||||
$onRejected,
|
||||
$expectedNextValue,
|
||||
$expectedNextReason,
|
||||
$expectedNextState
|
||||
)
|
||||
{
|
||||
$promise = new SyncPromise();
|
||||
$this->assertEquals(SyncPromise::PENDING, $promise->state);
|
||||
|
||||
$promise->reject($rejectedReason);
|
||||
$this->assertEquals(SyncPromise::REJECTED, $promise->state);
|
||||
|
||||
$this->setExpectedException(\Exception::class, 'Cannot resolve rejected promise');
|
||||
$promise->resolve('anything');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getRejectedPromiseData
|
||||
*/
|
||||
|
@ -15,17 +15,10 @@ class LexerTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testDissallowsUncommonControlCharacters()
|
||||
{
|
||||
try {
|
||||
$char = Utils::chr(0x0007);
|
||||
$this->lexOne($char);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (SyntaxError $error) {
|
||||
$msg = mb_substr($error->getMessage(), 0, 72, 'UTF-8');
|
||||
$this->assertEquals(
|
||||
'Syntax Error GraphQL (1:1) Cannot contain the invalid character "\u0007"',
|
||||
$msg
|
||||
);
|
||||
}
|
||||
$char = Utils::chr(0x0007);
|
||||
|
||||
$this->setExpectedExceptionRegExp(SyntaxError::class, '/' . preg_quote('Syntax Error GraphQL (1:1) Cannot contain the invalid character "\u0007"', '/') . '/');
|
||||
$this->lexOne($char);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,20 +107,14 @@ class LexerTest extends \PHPUnit_Framework_TestCase
|
||||
" ?\n" .
|
||||
"\n";
|
||||
|
||||
try {
|
||||
$this->lexOne($str);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertEquals(
|
||||
'Syntax Error GraphQL (3:5) Cannot parse the unexpected character "?".' . "\n" .
|
||||
"\n" .
|
||||
"2: \n" .
|
||||
"3: ?\n" .
|
||||
" ^\n" .
|
||||
"4: \n",
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
$this->setExpectedException(SyntaxError::class,
|
||||
'Syntax Error GraphQL (3:5) Cannot parse the unexpected character "?".' . "\n" .
|
||||
"\n" .
|
||||
"2: \n" .
|
||||
"3: ?\n" .
|
||||
" ^\n" .
|
||||
"4: \n");
|
||||
$this->lexOne($str);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -236,34 +223,33 @@ class LexerTest extends \PHPUnit_Framework_TestCase
|
||||
], (array) $this->lexOne('"\u1234\u5678\u90AB\uCDEF"'));
|
||||
}
|
||||
|
||||
public function reportsUsefulErrors() {
|
||||
return [
|
||||
['"', "Syntax Error GraphQL (1:2) Unterminated string.\n\n1: \"\n ^\n"],
|
||||
['"no end quote', "Syntax Error GraphQL (1:14) Unterminated string.\n\n1: \"no end quote\n ^\n"],
|
||||
["'single quotes'", "Syntax Error GraphQL (1:1) Unexpected single quote character ('), did you mean to use a double quote (\")?\n\n1: 'single quotes'\n ^\n"],
|
||||
['"contains unescaped \u0007 control char"', "Syntax Error GraphQL (1:21) Invalid character within String: \"\\u0007\"\n\n1: \"contains unescaped \\u0007 control char\"\n ^\n"],
|
||||
['"null-byte is not \u0000 end of file"', 'Syntax Error GraphQL (1:19) Invalid character within String: "\\u0000"' . "\n\n1: \"null-byte is not \\u0000 end of file\"\n ^\n"],
|
||||
['"multi' . "\n" . 'line"', "Syntax Error GraphQL (1:7) Unterminated string.\n\n1: \"multi\n ^\n2: line\"\n"],
|
||||
['"multi' . "\r" . 'line"', "Syntax Error GraphQL (1:7) Unterminated string.\n\n1: \"multi\n ^\n2: line\"\n"],
|
||||
['"bad \\z esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\z\n\n1: \"bad \\z esc\"\n ^\n"],
|
||||
['"bad \\x esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\x\n\n1: \"bad \\x esc\"\n ^\n"],
|
||||
['"bad \\u1 esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\u1 es\n\n1: \"bad \\u1 esc\"\n ^\n"],
|
||||
['"bad \\u0XX1 esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\u0XX1\n\n1: \"bad \\u0XX1 esc\"\n ^\n"],
|
||||
['"bad \\uXXXX esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\uXXXX\n\n1: \"bad \\uXXXX esc\"\n ^\n"],
|
||||
['"bad \\uFXXX esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\uFXXX\n\n1: \"bad \\uFXXX esc\"\n ^\n"],
|
||||
['"bad \\uXXXF esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\uXXXF\n\n1: \"bad \\uXXXF esc\"\n ^\n"],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider reportsUsefulErrors
|
||||
* @it lex reports useful string errors
|
||||
*/
|
||||
public function testReportsUsefulErrors()
|
||||
public function testReportsUsefulErrors($str, $expectedMessage)
|
||||
{
|
||||
$run = function($num, $str, $expectedMessage) {
|
||||
try {
|
||||
$this->lexOne($str);
|
||||
$this->fail('Expected exception not thrown in example: ' . $num);
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertEquals($expectedMessage, $e->getMessage(), "Test case $num failed");
|
||||
}
|
||||
};
|
||||
|
||||
$run(1, '"', "Syntax Error GraphQL (1:2) Unterminated string.\n\n1: \"\n ^\n");
|
||||
$run(2, '"no end quote', "Syntax Error GraphQL (1:14) Unterminated string.\n\n1: \"no end quote\n ^\n");
|
||||
$run(3, "'single quotes'", "Syntax Error GraphQL (1:1) Unexpected single quote character ('), did you mean to use a double quote (\")?\n\n1: 'single quotes'\n ^\n");
|
||||
$run(4, '"contains unescaped \u0007 control char"', "Syntax Error GraphQL (1:21) Invalid character within String: \"\\u0007\"\n\n1: \"contains unescaped \\u0007 control char\"\n ^\n");
|
||||
$run(5, '"null-byte is not \u0000 end of file"', 'Syntax Error GraphQL (1:19) Invalid character within String: "\\u0000"'."\n\n1: \"null-byte is not \\u0000 end of file\"\n ^\n");
|
||||
$run(6, '"multi'."\n".'line"', "Syntax Error GraphQL (1:7) Unterminated string.\n\n1: \"multi\n ^\n2: line\"\n");
|
||||
$run(7, '"multi'."\r".'line"', "Syntax Error GraphQL (1:7) Unterminated string.\n\n1: \"multi\n ^\n2: line\"\n");
|
||||
$run(8, '"bad \\z esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\z\n\n1: \"bad \\z esc\"\n ^\n");
|
||||
$run(9, '"bad \\x esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\x\n\n1: \"bad \\x esc\"\n ^\n");
|
||||
$run(10, '"bad \\u1 esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\u1 es\n\n1: \"bad \\u1 esc\"\n ^\n");
|
||||
$run(11, '"bad \\u0XX1 esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\u0XX1\n\n1: \"bad \\u0XX1 esc\"\n ^\n");
|
||||
$run(12, '"bad \\uXXXX esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\uXXXX\n\n1: \"bad \\uXXXX esc\"\n ^\n");
|
||||
$run(13, '"bad \\uFXXX esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\uFXXX\n\n1: \"bad \\uFXXX esc\"\n ^\n");
|
||||
$run(14, '"bad \\uXXXF esc"', "Syntax Error GraphQL (1:7) Invalid character escape sequence: \\uXXXF\n\n1: \"bad \\uXXXF esc\"\n ^\n");
|
||||
$this->setExpectedException(SyntaxError::class, $expectedMessage);
|
||||
$this->lexOne($str);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -337,28 +323,28 @@ class LexerTest extends \PHPUnit_Framework_TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function reportsUsefulNumberErrors()
|
||||
{
|
||||
return [
|
||||
[ '00', "Syntax Error GraphQL (1:2) Invalid number, unexpected digit after 0: \"0\"\n\n1: 00\n ^\n"],
|
||||
[ '+1', "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \"+\".\n\n1: +1\n ^\n"],
|
||||
[ '1.', "Syntax Error GraphQL (1:3) Invalid number, expected digit but got: <EOF>\n\n1: 1.\n ^\n"],
|
||||
[ '.123', "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \".\".\n\n1: .123\n ^\n"],
|
||||
[ '1.A', "Syntax Error GraphQL (1:3) Invalid number, expected digit but got: \"A\"\n\n1: 1.A\n ^\n"],
|
||||
[ '-A', "Syntax Error GraphQL (1:2) Invalid number, expected digit but got: \"A\"\n\n1: -A\n ^\n"],
|
||||
[ '1.0e', "Syntax Error GraphQL (1:5) Invalid number, expected digit but got: <EOF>\n\n1: 1.0e\n ^\n"],
|
||||
[ '1.0eA', "Syntax Error GraphQL (1:5) Invalid number, expected digit but got: \"A\"\n\n1: 1.0eA\n ^\n"],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider reportsUsefulNumberErrors
|
||||
* @it lex reports useful number errors
|
||||
*/
|
||||
public function testReportsUsefulNumberErrors()
|
||||
public function testReportsUsefulNumberErrors($str, $expectedMessage)
|
||||
{
|
||||
$run = function($num, $str, $expectedMessage) {
|
||||
try {
|
||||
$this->lexOne($str);
|
||||
$this->fail('Expected exception not thrown in example: ' . $num);
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertEquals($expectedMessage, $e->getMessage(), "Test case $num failed");
|
||||
}
|
||||
};
|
||||
|
||||
$run(0, '00', "Syntax Error GraphQL (1:2) Invalid number, unexpected digit after 0: \"0\"\n\n1: 00\n ^\n");
|
||||
$run(1, '+1', "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \"+\".\n\n1: +1\n ^\n");
|
||||
$run(2, '1.', "Syntax Error GraphQL (1:3) Invalid number, expected digit but got: <EOF>\n\n1: 1.\n ^\n");
|
||||
$run(3, '.123', "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \".\".\n\n1: .123\n ^\n");
|
||||
$run(4, '1.A', "Syntax Error GraphQL (1:3) Invalid number, expected digit but got: \"A\"\n\n1: 1.A\n ^\n");
|
||||
$run(5, '-A', "Syntax Error GraphQL (1:2) Invalid number, expected digit but got: \"A\"\n\n1: -A\n ^\n");
|
||||
$run(6, '1.0e', "Syntax Error GraphQL (1:5) Invalid number, expected digit but got: <EOF>\n\n1: 1.0e\n ^\n");
|
||||
$run(7, '1.0eA', "Syntax Error GraphQL (1:5) Invalid number, expected digit but got: \"A\"\n\n1: 1.0eA\n ^\n");
|
||||
$this->setExpectedException(SyntaxError::class, $expectedMessage);
|
||||
$this->lexOne($str);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -420,27 +406,27 @@ class LexerTest extends \PHPUnit_Framework_TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function reportsUsefulUnknownCharErrors()
|
||||
{
|
||||
$unicode1 = json_decode('"\u203B"');
|
||||
$unicode2 = json_decode('"\u200b"');
|
||||
|
||||
return [
|
||||
['..', "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \".\".\n\n1: ..\n ^\n"],
|
||||
['?', "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \"?\".\n\n1: ?\n ^\n"],
|
||||
[$unicode1, "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \"\\u203b\".\n\n1: $unicode1\n ^\n"],
|
||||
[$unicode2, "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \"\\u200b\".\n\n1: $unicode2\n ^\n"],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider reportsUsefulUnknownCharErrors
|
||||
* @it lex reports useful unknown character error
|
||||
*/
|
||||
public function testReportsUsefulUnknownCharErrors()
|
||||
public function testReportsUsefulUnknownCharErrors($str, $expectedMessage)
|
||||
{
|
||||
$run = function($num, $str, $expectedMessage) {
|
||||
try {
|
||||
$this->lexOne($str);
|
||||
$this->fail('Expected exception not thrown in example: ' . $num);
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertEquals($expectedMessage, $e->getMessage(), "Test case $num failed");
|
||||
}
|
||||
};
|
||||
$run(1, '..', "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \".\".\n\n1: ..\n ^\n");
|
||||
$run(2, '?', "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \"?\".\n\n1: ?\n ^\n");
|
||||
|
||||
$unicode = json_decode('"\u203B"');
|
||||
$run(3, $unicode, "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \"\\u203b\".\n\n1: $unicode\n ^\n");
|
||||
|
||||
$unicode = json_decode('"\u200b"');
|
||||
$run(4, $unicode, "Syntax Error GraphQL (1:1) Cannot parse the unexpected character \"\\u200b\".\n\n1: $unicode\n ^\n");
|
||||
$this->setExpectedException(SyntaxError::class, $expectedMessage);
|
||||
$this->lexOne($str);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -452,12 +438,8 @@ class LexerTest extends \PHPUnit_Framework_TestCase
|
||||
$lexer = new Lexer(new Source($q));
|
||||
$this->assertArraySubset(['kind' => Token::NAME, 'start' => 0, 'end' => 1, 'value' => 'a'], (array) $lexer->advance());
|
||||
|
||||
try {
|
||||
$lexer->advance();
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (SyntaxError $err) {
|
||||
$this->assertEquals('Syntax Error GraphQL (1:3) Invalid number, expected digit but got: "b"'."\n\n1: a-b\n ^\n", $err->getMessage());
|
||||
}
|
||||
$this->setExpectedException(SyntaxError::class, 'Syntax Error GraphQL (1:3) Invalid number, expected digit but got: "b"' . "\n\n1: a-b\n ^\n");
|
||||
$lexer->advance();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,65 +18,57 @@ use GraphQL\Utils\Utils;
|
||||
|
||||
class ParserTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @it asserts that a source to parse was provided
|
||||
*/
|
||||
public function testAssertsThatASourceToParseWasProvided()
|
||||
public function testAssertsThatASourceToParseIsNotNull()
|
||||
{
|
||||
try {
|
||||
Parser::parse(null);
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('GraphQL query body is expected to be string, but got NULL', $e->getMessage());
|
||||
}
|
||||
$this->setExpectedException(InvariantViolation::class, 'GraphQL query body is expected to be string, but got NULL');
|
||||
Parser::parse(null);
|
||||
}
|
||||
|
||||
try {
|
||||
Parser::parse(['a' => 'b']);
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('GraphQL query body is expected to be string, but got array', $e->getMessage());
|
||||
}
|
||||
public function testAssertsThatASourceToParseIsNotArray()
|
||||
{
|
||||
$this->setExpectedException(InvariantViolation::class, 'GraphQL query body is expected to be string, but got array');
|
||||
Parser::parse(['a' => 'b']);
|
||||
}
|
||||
|
||||
try {
|
||||
Parser::parse(new \stdClass());
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('GraphQL query body is expected to be string, but got stdClass', $e->getMessage());
|
||||
}
|
||||
public function testAssertsThatASourceToParseIsNotObject()
|
||||
{
|
||||
$this->setExpectedException(InvariantViolation::class, 'GraphQL query body is expected to be string, but got stdClass');
|
||||
Parser::parse(new \stdClass());
|
||||
}
|
||||
|
||||
public function parseProvidesUsefulErrors()
|
||||
{
|
||||
return [
|
||||
['{', "Syntax Error GraphQL (1:2) Expected Name, found <EOF>\n\n1: {\n ^\n", [1], [new SourceLocation(1, 2)]],
|
||||
['{ ...MissingOn }
|
||||
fragment MissingOn Type
|
||||
', "Syntax Error GraphQL (2:20) Expected \"on\", found Name \"Type\"\n\n1: { ...MissingOn }\n2: fragment MissingOn Type\n ^\n3: \n",],
|
||||
['{ field: {} }', "Syntax Error GraphQL (1:10) Expected Name, found {\n\n1: { field: {} }\n ^\n"],
|
||||
['notanoperation Foo { field }', "Syntax Error GraphQL (1:1) Unexpected Name \"notanoperation\"\n\n1: notanoperation Foo { field }\n ^\n"],
|
||||
['...', "Syntax Error GraphQL (1:1) Unexpected ...\n\n1: ...\n ^\n"],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider parseProvidesUsefulErrors
|
||||
* @it parse provides useful errors
|
||||
*/
|
||||
public function testParseProvidesUsefulErrors()
|
||||
public function testParseProvidesUsefulErrors($str, $expectedMessage, $expectedPositions = null, $expectedLocations = null)
|
||||
{
|
||||
$run = function($num, $str, $expectedMessage, $expectedPositions = null, $expectedLocations = null) {
|
||||
try {
|
||||
Parser::parse($str);
|
||||
$this->fail('Expected exception not thrown in example: ' . $num);
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertEquals($expectedMessage, $e->getMessage(), "Test case $num failed");
|
||||
try {
|
||||
Parser::parse($str);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertEquals($expectedMessage, $e->getMessage());
|
||||
|
||||
if ($expectedPositions) {
|
||||
$this->assertEquals($expectedPositions, $e->getPositions());
|
||||
}
|
||||
if ($expectedLocations) {
|
||||
$this->assertEquals($expectedLocations, $e->getLocations());
|
||||
}
|
||||
if ($expectedPositions) {
|
||||
$this->assertEquals($expectedPositions, $e->getPositions());
|
||||
}
|
||||
};
|
||||
|
||||
$run(0, '{', "Syntax Error GraphQL (1:2) Expected Name, found <EOF>\n\n1: {\n ^\n", [1], [new SourceLocation(1,2)]);
|
||||
$run(1,
|
||||
'{ ...MissingOn }
|
||||
fragment MissingOn Type
|
||||
',
|
||||
"Syntax Error GraphQL (2:20) Expected \"on\", found Name \"Type\"\n\n1: { ...MissingOn }\n2: fragment MissingOn Type\n ^\n3: \n"
|
||||
);
|
||||
|
||||
$run(2, '{ field: {} }', "Syntax Error GraphQL (1:10) Expected Name, found {\n\n1: { field: {} }\n ^\n");
|
||||
$run(3, 'notanoperation Foo { field }', "Syntax Error GraphQL (1:1) Unexpected Name \"notanoperation\"\n\n1: notanoperation Foo { field }\n ^\n");
|
||||
$run(4, '...', "Syntax Error GraphQL (1:1) Unexpected ...\n\n1: ...\n ^\n");
|
||||
if ($expectedLocations) {
|
||||
$this->assertEquals($expectedLocations, $e->getLocations());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,12 +76,8 @@ fragment MissingOn Type
|
||||
*/
|
||||
public function testParseProvidesUsefulErrorWhenUsingSource()
|
||||
{
|
||||
try {
|
||||
Parser::parse(new Source('query', 'MyQuery.graphql'));
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertEquals("Syntax Error MyQuery.graphql (1:6) Expected {, found <EOF>\n\n1: query\n ^\n", $e->getMessage());
|
||||
}
|
||||
$this->setExpectedException(SyntaxError::class, "Syntax Error MyQuery.graphql (1:6) Expected {, found <EOF>\n\n1: query\n ^\n");
|
||||
Parser::parse(new Source('query', 'MyQuery.graphql'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,15 +94,8 @@ fragment MissingOn Type
|
||||
*/
|
||||
public function testParsesConstantDefaultValues()
|
||||
{
|
||||
try {
|
||||
Parser::parse('query Foo($x: Complex = { a: { b: [ $var ] } }) { field }');
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertEquals(
|
||||
"Syntax Error GraphQL (1:37) Unexpected $\n\n" . '1: query Foo($x: Complex = { a: { b: [ $var ] } }) { field }' . "\n ^\n",
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
$this->setExpectedException(SyntaxError::class, "Syntax Error GraphQL (1:37) Unexpected $\n\n" . '1: query Foo($x: Complex = { a: { b: [ $var ] } }) { field }' . "\n ^\n");
|
||||
Parser::parse('query Foo($x: Complex = { a: { b: [ $var ] } }) { field }');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,13 +44,9 @@ class PrinterTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testProducesHelpfulErrorMessages()
|
||||
{
|
||||
$badAst1 = new \ArrayObject(array('random' => 'Data'));
|
||||
try {
|
||||
Printer::doPrint($badAst1);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('Invalid AST Node: {"random":"Data"}', $e->getMessage());
|
||||
}
|
||||
$badAst1 = new \ArrayObject(['random' => 'Data']);
|
||||
$this->setExpectedException(\Exception::class, 'Invalid AST Node: {"random":"Data"}');
|
||||
Printer::doPrint($badAst1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -557,11 +557,8 @@ type Hello {
|
||||
public function testUnionFailsWithNoTypes()
|
||||
{
|
||||
$body = 'union Hello = |';
|
||||
try {
|
||||
Parser::parse($body);
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertContains('Syntax Error GraphQL (1:16) Expected Name, found <EOF>', $e->getMessage());
|
||||
}
|
||||
$this->setExpectedExceptionRegExp(SyntaxError::class, '/' . preg_quote('Syntax Error GraphQL (1:16) Expected Name, found <EOF>', '/') . '/');
|
||||
Parser::parse($body);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -570,11 +567,8 @@ type Hello {
|
||||
public function testUnionFailsWithLeadingDoublePipe()
|
||||
{
|
||||
$body = 'union Hello = || Wo | Rld';
|
||||
try {
|
||||
Parser::parse($body);
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertContains('Syntax Error GraphQL (1:16) Expected Name, found |', $e->getMessage());
|
||||
}
|
||||
$this->setExpectedExceptionRegExp(SyntaxError::class, '/' . preg_quote('Syntax Error GraphQL (1:16) Expected Name, found |', '/') . '/');
|
||||
Parser::parse($body);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -583,11 +577,8 @@ type Hello {
|
||||
public function testUnionFailsWithDoublePipe()
|
||||
{
|
||||
$body = 'union Hello = Wo || Rld';
|
||||
try {
|
||||
Parser::parse($body);
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertContains('Syntax Error GraphQL (1:19) Expected Name, found |', $e->getMessage());
|
||||
}
|
||||
$this->setExpectedExceptionRegExp(SyntaxError::class, '/' . preg_quote('Syntax Error GraphQL (1:19) Expected Name, found |', '/') . '/');
|
||||
Parser::parse($body);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -596,11 +587,8 @@ type Hello {
|
||||
public function testUnionFailsWithTrailingPipe()
|
||||
{
|
||||
$body = 'union Hello = | Wo | Rld |';
|
||||
try {
|
||||
Parser::parse($body);
|
||||
} catch (SyntaxError $e) {
|
||||
$this->assertContains('Syntax Error GraphQL (1:27) Expected Name, found <EOF>', $e->getMessage());
|
||||
}
|
||||
$this->setExpectedExceptionRegExp(SyntaxError::class, '/' . preg_quote('Syntax Error GraphQL (1:27) Expected Name, found <EOF>', '/') . '/');
|
||||
Parser::parse($body);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,6 +26,23 @@ class SerializationTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertNodesAreEqual($parsedAst, $actualAst);
|
||||
}
|
||||
|
||||
public function testSerializeSupportsNoLocationOption()
|
||||
{
|
||||
$kitchenSink = file_get_contents(__DIR__ . '/kitchen-sink.graphql');
|
||||
$ast = Parser::parse($kitchenSink, ['noLocation' => true]);
|
||||
$expectedAst = json_decode(file_get_contents(__DIR__ . '/kitchen-sink-noloc.ast'), true);
|
||||
$this->assertEquals($expectedAst, $ast->toArray(true));
|
||||
}
|
||||
|
||||
public function testUnserializeSupportsNoLocationOption()
|
||||
{
|
||||
$kitchenSink = file_get_contents(__DIR__ . '/kitchen-sink.graphql');
|
||||
$serializedAst = json_decode(file_get_contents(__DIR__ . '/kitchen-sink-noloc.ast'), true);
|
||||
$actualAst = AST::fromArray($serializedAst);
|
||||
$parsedAst = Parser::parse($kitchenSink, ['noLocation' => true]);
|
||||
$this->assertNodesAreEqual($parsedAst, $actualAst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two nodes by actually iterating over all NodeLists, properly comparing locations (ignoring tokens), etc
|
||||
*
|
||||
|
637
tests/Language/kitchen-sink-noloc.ast
Normal file
637
tests/Language/kitchen-sink-noloc.ast
Normal file
@ -0,0 +1,637 @@
|
||||
{
|
||||
"kind": "Document",
|
||||
"definitions": [
|
||||
{
|
||||
"kind": "OperationDefinition",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "queryName"
|
||||
},
|
||||
"operation": "query",
|
||||
"variableDefinitions": [
|
||||
{
|
||||
"kind": "VariableDefinition",
|
||||
"variable": {
|
||||
"kind": "Variable",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "foo"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"kind": "NamedType",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "ComplexType"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "VariableDefinition",
|
||||
"variable": {
|
||||
"kind": "Variable",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "site"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"kind": "NamedType",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "Site"
|
||||
}
|
||||
},
|
||||
"defaultValue": {
|
||||
"kind": "EnumValue",
|
||||
"value": "MOBILE"
|
||||
}
|
||||
}
|
||||
],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "node"
|
||||
},
|
||||
"alias": {
|
||||
"kind": "Name",
|
||||
"value": "whoever123is"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "ListValue",
|
||||
"values": [
|
||||
{
|
||||
"kind": "IntValue",
|
||||
"value": "123"
|
||||
},
|
||||
{
|
||||
"kind": "IntValue",
|
||||
"value": "456"
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "id"
|
||||
}
|
||||
}
|
||||
],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "id"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": []
|
||||
},
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"typeCondition": {
|
||||
"kind": "NamedType",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "User"
|
||||
}
|
||||
},
|
||||
"directives": [
|
||||
{
|
||||
"kind": "Directive",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "defer"
|
||||
},
|
||||
"arguments": []
|
||||
}
|
||||
],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "field2"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "id"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": []
|
||||
},
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "field1"
|
||||
},
|
||||
"alias": {
|
||||
"kind": "Name",
|
||||
"value": "alias"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "IntValue",
|
||||
"value": "10"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "first"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "Variable",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "foo"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "after"
|
||||
}
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
{
|
||||
"kind": "Directive",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "include"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "Variable",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "foo"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "if"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "id"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": []
|
||||
},
|
||||
{
|
||||
"kind": "FragmentSpread",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "frag"
|
||||
},
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"directives": [
|
||||
{
|
||||
"kind": "Directive",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "skip"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "Variable",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "foo"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "unless"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "id"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "id"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "OperationDefinition",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "likeStory"
|
||||
},
|
||||
"operation": "mutation",
|
||||
"variableDefinitions": [],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "like"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "IntValue",
|
||||
"value": "123"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "story"
|
||||
}
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
{
|
||||
"kind": "Directive",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "defer"
|
||||
},
|
||||
"arguments": []
|
||||
}
|
||||
],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "story"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "id"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "OperationDefinition",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "StoryLikeSubscription"
|
||||
},
|
||||
"operation": "subscription",
|
||||
"variableDefinitions": [
|
||||
{
|
||||
"kind": "VariableDefinition",
|
||||
"variable": {
|
||||
"kind": "Variable",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "input"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"kind": "NamedType",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "StoryLikeSubscribeInput"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "storyLikeSubscribe"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "Variable",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "input"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "input"
|
||||
}
|
||||
}
|
||||
],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "story"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "likers"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "count"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "likeSentence"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "text"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "FragmentDefinition",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "frag"
|
||||
},
|
||||
"typeCondition": {
|
||||
"kind": "NamedType",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "Friend"
|
||||
}
|
||||
},
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "foo"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "Variable",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "size"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "size"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "Variable",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "b"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "bar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "ObjectValue",
|
||||
"fields": [
|
||||
{
|
||||
"kind": "ObjectField",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "key"
|
||||
},
|
||||
"value": {
|
||||
"kind": "StringValue",
|
||||
"value": "value"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "obj"
|
||||
}
|
||||
}
|
||||
],
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "OperationDefinition",
|
||||
"operation": "query",
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "unnamed"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "BooleanValue",
|
||||
"value": true
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "truthy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "BooleanValue",
|
||||
"value": false
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "falsey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Argument",
|
||||
"value": {
|
||||
"kind": "NullValue"
|
||||
},
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "nullish"
|
||||
}
|
||||
}
|
||||
],
|
||||
"directives": []
|
||||
},
|
||||
{
|
||||
"kind": "Field",
|
||||
"name": {
|
||||
"kind": "Name",
|
||||
"value": "query"
|
||||
},
|
||||
"arguments": [],
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -56,8 +56,7 @@
|
||||
},
|
||||
"value": "ComplexType"
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "VariableDefinition",
|
||||
@ -199,10 +198,8 @@
|
||||
},
|
||||
"value": "id"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
"directives": []
|
||||
},
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
@ -264,7 +261,6 @@
|
||||
},
|
||||
"value": "field2"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
@ -288,10 +284,8 @@
|
||||
},
|
||||
"value": "id"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
"directives": []
|
||||
},
|
||||
{
|
||||
"kind": "Field",
|
||||
@ -440,10 +434,8 @@
|
||||
},
|
||||
"value": "id"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
"directives": []
|
||||
},
|
||||
{
|
||||
"kind": "FragmentSpread",
|
||||
@ -476,7 +468,6 @@
|
||||
"start": 574,
|
||||
"end": 614
|
||||
},
|
||||
"typeCondition": null,
|
||||
"directives": [
|
||||
{
|
||||
"kind": "Directive",
|
||||
@ -547,10 +538,8 @@
|
||||
},
|
||||
"value": "id"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -561,7 +550,6 @@
|
||||
"start": 619,
|
||||
"end": 639
|
||||
},
|
||||
"typeCondition": null,
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
@ -584,10 +572,8 @@
|
||||
},
|
||||
"value": "id"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -636,7 +622,6 @@
|
||||
},
|
||||
"value": "like"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
@ -701,7 +686,6 @@
|
||||
},
|
||||
"value": "story"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
@ -725,10 +709,8 @@
|
||||
},
|
||||
"value": "id"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -790,8 +772,7 @@
|
||||
},
|
||||
"value": "StoryLikeSubscribeInput"
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"directives": [],
|
||||
@ -816,7 +797,6 @@
|
||||
},
|
||||
"value": "storyLikeSubscribe"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
@ -871,7 +851,6 @@
|
||||
},
|
||||
"value": "story"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
@ -895,7 +874,6 @@
|
||||
},
|
||||
"value": "likers"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
@ -919,10 +897,8 @@
|
||||
},
|
||||
"value": "count"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -941,7 +917,6 @@
|
||||
},
|
||||
"value": "likeSentence"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
@ -965,10 +940,8 @@
|
||||
},
|
||||
"value": "text"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1033,7 +1006,6 @@
|
||||
},
|
||||
"value": "foo"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
@ -1143,8 +1115,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1155,9 +1126,7 @@
|
||||
"start": 1020,
|
||||
"end": 1086
|
||||
},
|
||||
"name": null,
|
||||
"operation": "query",
|
||||
"variableDefinitions": null,
|
||||
"directives": [],
|
||||
"selectionSet": {
|
||||
"kind": "SelectionSet",
|
||||
@ -1180,7 +1149,6 @@
|
||||
},
|
||||
"value": "unnamed"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [
|
||||
{
|
||||
"kind": "Argument",
|
||||
@ -1251,8 +1219,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
"directives": []
|
||||
},
|
||||
{
|
||||
"kind": "Field",
|
||||
@ -1268,10 +1235,8 @@
|
||||
},
|
||||
"value": "query"
|
||||
},
|
||||
"alias": null,
|
||||
"arguments": [],
|
||||
"directives": [],
|
||||
"selectionSet": null
|
||||
"directives": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -158,27 +158,20 @@ class RequestParsingTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testFailsParsingInvalidRawJsonRequest()
|
||||
public function testFailsParsingInvalidRawJsonRequestRaw()
|
||||
{
|
||||
$body = 'not really{} a json';
|
||||
|
||||
try {
|
||||
$this->setExpectedException(RequestError::class, 'Could not parse JSON: Syntax error');
|
||||
$this->parseRawRequest('application/json', $body);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (RequestError $e) {
|
||||
$this->assertEquals('Could not parse JSON: Syntax error', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
public function testFailsParsingInvalidRawJsonRequestPsr()
|
||||
{
|
||||
$body = 'not really{} a json';
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class, 'PSR-7 request is expected to provide parsed body for "application/json" requests but got null');
|
||||
$this->parsePsrRequest('application/json', $body);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
// Expecting parsing exception to be thrown somewhere else:
|
||||
$this->assertEquals(
|
||||
'PSR-7 request is expected to provide parsed body for "application/json" requests but got null',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testFailsParsingNonPreParsedPsrRequest()
|
||||
@ -197,82 +190,62 @@ class RequestParsingTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
// There is no equivalent for psr request, because it should throw
|
||||
|
||||
public function testFailsParsingNonArrayOrObjectJsonRequest()
|
||||
public function testFailsParsingNonArrayOrObjectJsonRequestRaw()
|
||||
{
|
||||
$body = '"str"';
|
||||
|
||||
try {
|
||||
$this->setExpectedException(RequestError::class, 'GraphQL Server expects JSON object or array, but got "str"');
|
||||
$this->parseRawRequest('application/json', $body);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (RequestError $e) {
|
||||
$this->assertEquals('GraphQL Server expects JSON object or array, but got "str"', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
public function testFailsParsingNonArrayOrObjectJsonRequestPsr()
|
||||
{
|
||||
$body = '"str"';
|
||||
|
||||
$this->setExpectedException(RequestError::class, 'GraphQL Server expects JSON object or array, but got "str"');
|
||||
$this->parsePsrRequest('application/json', $body);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (RequestError $e) {
|
||||
$this->assertEquals('GraphQL Server expects JSON object or array, but got "str"', $e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function testFailsParsingInvalidContentType()
|
||||
public function testFailsParsingInvalidContentTypeRaw()
|
||||
{
|
||||
$contentType = 'not-supported-content-type';
|
||||
$body = 'test';
|
||||
|
||||
try {
|
||||
$this->setExpectedException(RequestError::class, 'Unexpected content type: "not-supported-content-type"');
|
||||
$this->parseRawRequest($contentType, $body);
|
||||
}
|
||||
|
||||
public function testFailsParsingInvalidContentTypePsr()
|
||||
{
|
||||
$contentType = 'not-supported-content-type';
|
||||
$body = 'test';
|
||||
|
||||
$this->setExpectedException(RequestError::class, 'Unexpected content type: "not-supported-content-type"');
|
||||
$this->parseRawRequest($contentType, $body);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (RequestError $e) {
|
||||
$this->assertEquals('Unexpected content type: "not-supported-content-type"', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$this->parsePsrRequest($contentType, $body);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (RequestError $e) {
|
||||
$this->assertEquals('Unexpected content type: "not-supported-content-type"', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testFailsWithMissingContentType()
|
||||
public function testFailsWithMissingContentTypeRaw()
|
||||
{
|
||||
try {
|
||||
$this->setExpectedException(RequestError::class, 'Missing "Content-Type" header');
|
||||
$this->parseRawRequest(null, 'test');
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (RequestError $e) {
|
||||
$this->assertEquals('Missing "Content-Type" header', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
public function testFailsWithMissingContentTypePsr()
|
||||
{
|
||||
$this->setExpectedException(RequestError::class, 'Missing "Content-Type" header');
|
||||
$this->parsePsrRequest(null, 'test');
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (RequestError $e) {
|
||||
$this->assertEquals('Missing "Content-Type" header', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testFailsOnMethodsOtherThanPostOrGet()
|
||||
public function testFailsOnMethodsOtherThanPostOrGetRaw()
|
||||
{
|
||||
$body = [
|
||||
'query' => '{my query}',
|
||||
];
|
||||
$this->setExpectedException(RequestError::class, 'HTTP Method "PUT" is not supported');
|
||||
$this->parseRawRequest('application/json', json_encode([]), "PUT");
|
||||
}
|
||||
|
||||
try {
|
||||
$this->parseRawRequest('application/json', json_encode($body), "PUT");
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (RequestError $e) {
|
||||
$this->assertEquals('HTTP Method "PUT" is not supported', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$this->parsePsrRequest('application/json', json_encode($body), "PUT");
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (RequestError $e) {
|
||||
$this->assertEquals('HTTP Method "PUT" is not supported', $e->getMessage());
|
||||
}
|
||||
public function testFailsOnMethodsOtherThanPostOrGetPsr()
|
||||
{
|
||||
$this->setExpectedException(RequestError::class, 'HTTP Method "PUT" is not supported');
|
||||
$this->parsePsrRequest('application/json', json_encode([]), "PUT");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,6 +4,7 @@ namespace GraphQL\Tests;
|
||||
use GraphQL\Error\Debug;
|
||||
use GraphQL\Error\FormattedError;
|
||||
use GraphQL\Error\InvariantViolation;
|
||||
use GraphQL\Error\SyntaxError;
|
||||
use GraphQL\Error\UserError;
|
||||
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
|
||||
use GraphQL\Schema;
|
||||
@ -38,197 +39,227 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals(500, $server->getUnexpectedErrorStatus());
|
||||
$this->assertEquals(DocumentValidator::allRules(), $server->getValidationRules());
|
||||
|
||||
try {
|
||||
$server->getSchema();
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Schema query must be Object Type but got: NULL', $e->getMessage());
|
||||
}
|
||||
$this->setExpectedException(InvariantViolation::class, 'Schema query must be Object Type but got: NULL');
|
||||
$server->getSchema();
|
||||
}
|
||||
|
||||
public function testCannotUseSetQueryTypeAndSetSchema()
|
||||
{
|
||||
$queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Schema on Server: Query Type is already set ' .
|
||||
'(GraphQL\Server::setQueryType is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->setQueryType($queryType)
|
||||
->setSchema($schema);
|
||||
}
|
||||
|
||||
public function testCannotUseSetMutationTypeAndSetSchema()
|
||||
{
|
||||
$mutationType = $queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Schema on Server: Mutation Type is already set ' .
|
||||
'(GraphQL\Server::setMutationType is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->setMutationType($mutationType)
|
||||
->setSchema($schema);
|
||||
}
|
||||
|
||||
public function testCannotUseSetSubscriptionTypeAndSetSchema()
|
||||
{
|
||||
$subscriptionType = $queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Schema on Server: Subscription Type is already set ' .
|
||||
'(GraphQL\Server::setSubscriptionType is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->setSubscriptionType($subscriptionType)
|
||||
->setSchema($schema);
|
||||
}
|
||||
|
||||
public function testCannotUseSetDirectivesAndSetSchema()
|
||||
{
|
||||
$queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Schema on Server: Directives are already set ' .
|
||||
'(GraphQL\Server::setDirectives is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->setDirectives(Directive::getInternalDirectives())
|
||||
->setSchema($schema);
|
||||
}
|
||||
|
||||
public function testCannotUseAddTypesAndSetSchema()
|
||||
{
|
||||
$mutationType = $queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Schema on Server: Additional types are already set ' .
|
||||
'(GraphQL\Server::addTypes is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->addTypes([$queryType, $mutationType])
|
||||
->setSchema($schema);
|
||||
}
|
||||
|
||||
public function testCannotUseSetTypeResolutionStrategyAndSetSchema()
|
||||
{
|
||||
$mutationType = $queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Schema on Server: Type Resolution Strategy is already set ' .
|
||||
'(GraphQL\Server::setTypeResolutionStrategy is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->setTypeResolutionStrategy(new EagerResolution([$queryType, $mutationType]))
|
||||
->setSchema($schema);
|
||||
}
|
||||
|
||||
public function testCannotUseSetSchemaAndSetQueryType()
|
||||
{
|
||||
$queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Query Type on Server: Schema is already set ' .
|
||||
'(GraphQL\Server::setQueryType is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setQueryType($queryType);
|
||||
}
|
||||
|
||||
public function testCannotUseSetSchemaAndSetMutationType()
|
||||
{
|
||||
$mutationType = $queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Mutation Type on Server: Schema is already set ' .
|
||||
'(GraphQL\Server::setMutationType is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setMutationType($mutationType);
|
||||
}
|
||||
|
||||
public function testCannotUseSetSchemaAndSetSubscriptionType()
|
||||
{
|
||||
$subscriptionType = $queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Subscription Type on Server: Schema is already set ' .
|
||||
'(GraphQL\Server::setSubscriptionType is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setSubscriptionType($subscriptionType);
|
||||
}
|
||||
|
||||
public function testCannotUseSetSchemaAndSetDirectives()
|
||||
{
|
||||
$queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Directives on Server: Schema is already set ' .
|
||||
'(GraphQL\Server::setDirectives is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setDirectives([]);
|
||||
|
||||
}
|
||||
|
||||
public function testCannotUseSetSchemaAndAddTypes()
|
||||
{
|
||||
$mutationType = $queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Types on Server: Schema is already set ' .
|
||||
'(GraphQL\Server::addTypes is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->addTypes([$queryType, $mutationType]);
|
||||
}
|
||||
|
||||
public function testCanUseSetSchemaAndAddEmptyTypes()
|
||||
{
|
||||
$queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
// But empty types should work (as they don't change anything):
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->addTypes([]);
|
||||
}
|
||||
|
||||
public function testCannotUseSetSchemaAndSetTypeResolutionStrategy()
|
||||
{
|
||||
$mutationType = $queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Type Resolution Strategy on Server: Schema is already set ' .
|
||||
'(GraphQL\Server::setTypeResolutionStrategy is mutually exclusive with GraphQL\Server::setSchema)');
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setTypeResolutionStrategy(new EagerResolution([$queryType, $mutationType]));
|
||||
|
||||
}
|
||||
|
||||
public function testCannotUseSetSchemaAndSetSchema()
|
||||
{
|
||||
$queryType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
$schema = new Schema([
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
$this->setExpectedException(InvariantViolation::class,
|
||||
'Cannot set Schema on Server: Different schema is already set');
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setSchema(new Schema(['query' => $queryType]));
|
||||
$this->fail('Expected exception not thrown');
|
||||
}
|
||||
|
||||
public function testSchemaDefinition()
|
||||
{
|
||||
$mutationType = $queryType = $subscriptionType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||
|
||||
$schema = new Schema([
|
||||
'query' => $queryType
|
||||
'query' => $queryType,
|
||||
]);
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setQueryType($queryType)
|
||||
->setSchema($schema);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Schema on Server: Query Type is already set '.
|
||||
'(GraphQL\Server::setQueryType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setMutationType($mutationType)
|
||||
->setSchema($schema);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Schema on Server: Mutation Type is already set '.
|
||||
'(GraphQL\Server::setMutationType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setSubscriptionType($subscriptionType)
|
||||
->setSchema($schema);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Schema on Server: Subscription Type is already set '.
|
||||
'(GraphQL\Server::setSubscriptionType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setDirectives(Directive::getInternalDirectives())
|
||||
->setSchema($schema);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Schema on Server: Directives are already set '.
|
||||
'(GraphQL\Server::setDirectives is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->addTypes([$queryType, $mutationType])
|
||||
->setSchema($schema);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Schema on Server: Additional types are already set '.
|
||||
'(GraphQL\Server::addTypes is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setTypeResolutionStrategy(new EagerResolution([$queryType, $mutationType]))
|
||||
->setSchema($schema);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Schema on Server: Type Resolution Strategy is already set '.
|
||||
'(GraphQL\Server::setTypeResolutionStrategy is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setQueryType($queryType);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Query Type on Server: Schema is already set '.
|
||||
'(GraphQL\Server::setQueryType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setMutationType($mutationType);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Mutation Type on Server: Schema is already set '.
|
||||
'(GraphQL\Server::setMutationType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setSubscriptionType($subscriptionType);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Subscription Type on Server: Schema is already set '.
|
||||
'(GraphQL\Server::setSubscriptionType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setDirectives([]);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Directives on Server: Schema is already set '.
|
||||
'(GraphQL\Server::setDirectives is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->addTypes([$queryType, $mutationType]);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Types on Server: Schema is already set '.
|
||||
'(GraphQL\Server::addTypes is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
// But empty types should work (as they don't change anything):
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->addTypes([]);
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setTypeResolutionStrategy(new EagerResolution([$queryType, $mutationType]));
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Type Resolution Strategy on Server: Schema is already set '.
|
||||
'(GraphQL\Server::setTypeResolutionStrategy is mutually exclusive with GraphQL\Server::setSchema)',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Server::create()
|
||||
->setSchema($schema)
|
||||
->setSchema(new Schema(['query' => $queryType]));
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set Schema on Server: Different schema is already set',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// This should not throw:
|
||||
$server = Server::create()
|
||||
->setSchema($schema);
|
||||
|
||||
@ -273,12 +304,9 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
||||
$ast = $server->parse('{q}');
|
||||
$this->assertInstanceOf('GraphQL\Language\AST\DocumentNode', $ast);
|
||||
|
||||
try {
|
||||
$server->parse('{q');
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (\GraphQL\Error\SyntaxError $e) {
|
||||
$this->assertContains('{q', $e->getMessage());
|
||||
}
|
||||
$this->setExpectedExceptionRegExp(SyntaxError::class, '/' . preg_quote('{q', '/') . '/');
|
||||
$server->parse('{q');
|
||||
$this->fail('Expected exception not thrown');
|
||||
}
|
||||
|
||||
public function testValidate()
|
||||
@ -292,16 +320,9 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertInternalType('array', $errors);
|
||||
$this->assertNotEmpty($errors);
|
||||
|
||||
try {
|
||||
$server = Server::create();
|
||||
$server->validate($ast);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot validate, schema contains errors: Schema query must be Object Type but got: NULL',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
$this->setExpectedException(InvariantViolation::class, 'Cannot validate, schema contains errors: Schema query must be Object Type but got: NULL');
|
||||
$server = Server::create();
|
||||
$server->validate($ast);
|
||||
}
|
||||
|
||||
public function testPromiseAdapter()
|
||||
@ -315,15 +336,8 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame($adapter1, $server->getPromiseAdapter());
|
||||
$server->setPromiseAdapter($adapter1);
|
||||
|
||||
try {
|
||||
$server->setPromiseAdapter($adapter2);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Cannot set promise adapter: Different adapter is already set',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
$this->setExpectedException(InvariantViolation::class, 'Cannot set promise adapter: Different adapter is already set');
|
||||
$server->setPromiseAdapter($adapter2);
|
||||
}
|
||||
|
||||
public function testValidationRules()
|
||||
@ -583,4 +597,4 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertInternalType('array', $output);
|
||||
$this->assertEquals($expectedOutput, $output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -526,8 +526,8 @@ class ResolutionTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals($eager->resolvePossibleTypes($this->mention), $lazy->resolvePossibleTypes($this->mention));
|
||||
}
|
||||
|
||||
public function testLazyThrowsOnInvalidLoadedType()
|
||||
{
|
||||
private function createLazy(){
|
||||
|
||||
$descriptor = [
|
||||
'version' => '1.0',
|
||||
'typeMap' => [
|
||||
@ -557,37 +557,29 @@ class ResolutionTest extends \PHPUnit_Framework_TestCase
|
||||
$value = $lazy->resolveType('null');
|
||||
$this->assertEquals(null, $value);
|
||||
|
||||
try {
|
||||
$lazy->resolveType('int');
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
"Lazy Type Resolution Error: Expecting GraphQL Type instance, but got integer",
|
||||
$e->getMessage()
|
||||
);
|
||||
return $lazy;
|
||||
}
|
||||
|
||||
}
|
||||
public function testLazyThrowsOnInvalidLoadedType()
|
||||
{
|
||||
$lazy = $this->createLazy();
|
||||
$this->setExpectedException(InvariantViolation::class, "Lazy Type Resolution Error: Expecting GraphQL Type instance, but got integer");
|
||||
$lazy->resolveType('int');
|
||||
}
|
||||
|
||||
try {
|
||||
$tmp = new InterfaceType(['name' => 'a', 'fields' => []]);
|
||||
$lazy->resolvePossibleTypes($tmp);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Lazy Type Resolution Error: Implementation null of interface a is expected to be instance of ObjectType, but got NULL',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
public function testLazyThrowsOnInvalidLoadedPossibleType()
|
||||
{
|
||||
$tmp = new InterfaceType(['name' => 'a', 'fields' => []]);
|
||||
$lazy = $this->createLazy();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Lazy Type Resolution Error: Implementation null of interface a is expected to be instance of ObjectType, but got NULL');
|
||||
$lazy->resolvePossibleTypes($tmp);
|
||||
}
|
||||
|
||||
try {
|
||||
$tmp = new InterfaceType(['name' => 'b', 'fields' => []]);
|
||||
$lazy->resolvePossibleTypes($tmp);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'Lazy Type Resolution Error: Expecting GraphQL Type instance, but got integer',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
public function testLazyThrowsOnInvalidLoadedPossibleTypeWithInteger()
|
||||
{
|
||||
$tmp = new InterfaceType(['name' => 'b', 'fields' => []]);
|
||||
$lazy = $this->createLazy();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Lazy Type Resolution Error: Expecting GraphQL Type instance, but got integer');
|
||||
$lazy->resolvePossibleTypes($tmp);
|
||||
}
|
||||
}
|
||||
|
@ -22,82 +22,89 @@ class ScalarSerializationTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame(-1, $intType->serialize(-1));
|
||||
$this->assertSame(100000, $intType->serialize(1e5));
|
||||
$this->assertSame(0, $intType->serialize(0e5));
|
||||
|
||||
// The GraphQL specification does not allow serializing non-integer values
|
||||
// as Int to avoid accidental data loss.
|
||||
try {
|
||||
$intType->serialize(0.1);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Int cannot represent non-integer value: 0.1', $e->getMessage());
|
||||
}
|
||||
try {
|
||||
$intType->serialize(1.1);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Int cannot represent non-integer value: 1.1', $e->getMessage());
|
||||
}
|
||||
try {
|
||||
$intType->serialize(-1.1);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Int cannot represent non-integer value: -1.1', $e->getMessage());
|
||||
}
|
||||
try {
|
||||
$intType->serialize('-1.1');
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Int cannot represent non-integer value: "-1.1"', $e->getMessage());
|
||||
}
|
||||
|
||||
// Maybe a safe PHP int, but bigger than 2^32, so not
|
||||
// representable as a GraphQL Int
|
||||
try {
|
||||
$intType->serialize(9876504321);
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Int cannot represent non 32-bit signed integer value: 9876504321', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$intType->serialize(-9876504321);
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Int cannot represent non 32-bit signed integer value: -9876504321', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$intType->serialize(1e100);
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Int cannot represent non 32-bit signed integer value: 1.0E+100', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$intType->serialize(-1e100);
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Int cannot represent non 32-bit signed integer value: -1.0E+100', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$intType->serialize('one');
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Int cannot represent non 32-bit signed integer value: "one"', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$intType->serialize('');
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Int cannot represent non 32-bit signed integer value: (empty string)', $e->getMessage());
|
||||
}
|
||||
|
||||
$this->assertSame(0, $intType->serialize(false));
|
||||
$this->assertSame(1, $intType->serialize(true));
|
||||
}
|
||||
|
||||
public function testSerializesOutputIntCannotRepresentFloat1()
|
||||
{
|
||||
// The GraphQL specification does not allow serializing non-integer values
|
||||
// as Int to avoid accidental data loss.
|
||||
$intType = Type::int();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Int cannot represent non-integer value: 0.1');
|
||||
$intType->serialize(0.1);
|
||||
}
|
||||
|
||||
public function testSerializesOutputIntCannotRepresentFloat2()
|
||||
{
|
||||
$intType = Type::int();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Int cannot represent non-integer value: 1.1');
|
||||
$intType->serialize(1.1);
|
||||
|
||||
}
|
||||
|
||||
public function testSerializesOutputIntCannotRepresentNegativeFloat()
|
||||
{
|
||||
$intType = Type::int();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Int cannot represent non-integer value: -1.1');
|
||||
$intType->serialize(-1.1);
|
||||
|
||||
}
|
||||
|
||||
public function testSerializesOutputIntCannotRepresentNumericString()
|
||||
{
|
||||
$intType = Type::int();
|
||||
$this->setExpectedException(InvariantViolation::class, '');
|
||||
$intType->serialize('Int cannot represent non-integer value: "-1.1"');
|
||||
|
||||
}
|
||||
|
||||
public function testSerializesOutputIntCannotRepresentBiggerThan32Bits()
|
||||
{
|
||||
// Maybe a safe PHP int, but bigger than 2^32, so not
|
||||
// representable as a GraphQL Int
|
||||
$intType = Type::int();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Int cannot represent non 32-bit signed integer value: 9876504321');
|
||||
$intType->serialize(9876504321);
|
||||
|
||||
}
|
||||
|
||||
public function testSerializesOutputIntCannotRepresentLowerThan32Bits()
|
||||
{
|
||||
$intType = Type::int();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Int cannot represent non 32-bit signed integer value: -9876504321');
|
||||
$intType->serialize(-9876504321);
|
||||
}
|
||||
|
||||
public function testSerializesOutputIntCannotRepresentBiggerThanSigned32Bits()
|
||||
{
|
||||
$intType = Type::int();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Int cannot represent non 32-bit signed integer value: 1.0E+100');
|
||||
$intType->serialize(1e100);
|
||||
}
|
||||
|
||||
public function testSerializesOutputIntCannotRepresentLowerThanSigned32Bits()
|
||||
{
|
||||
$intType = Type::int();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Int cannot represent non 32-bit signed integer value: -1.0E+100');
|
||||
$intType->serialize(-1e100);
|
||||
}
|
||||
|
||||
public function testSerializesOutputIntCannotRepresentString()
|
||||
{
|
||||
$intType = Type::int();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Int cannot represent non 32-bit signed integer value: "one"');
|
||||
$intType->serialize('one');
|
||||
|
||||
}
|
||||
|
||||
public function testSerializesOutputIntCannotRepresentEmptyString()
|
||||
{
|
||||
$intType = Type::int();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Int cannot represent non 32-bit signed integer value: (empty string)');
|
||||
$intType->serialize('');
|
||||
}
|
||||
|
||||
/**
|
||||
* @it serializes output float
|
||||
*/
|
||||
@ -113,25 +120,24 @@ class ScalarSerializationTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame(1.1, $floatType->serialize(1.1));
|
||||
$this->assertSame(-1.1, $floatType->serialize(-1.1));
|
||||
$this->assertSame(-1.1, $floatType->serialize('-1.1'));
|
||||
|
||||
try {
|
||||
$floatType->serialize('one');
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Float cannot represent non numeric value: "one"', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$floatType->serialize('');
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('Float cannot represent non numeric value: (empty string)', $e->getMessage());
|
||||
}
|
||||
|
||||
$this->assertSame(0.0, $floatType->serialize(false));
|
||||
$this->assertSame(1.0, $floatType->serialize(true));
|
||||
}
|
||||
|
||||
public function testSerializesOutputFloatCannotRepresentString()
|
||||
{
|
||||
$floatType = Type::float();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Float cannot represent non numeric value: "one"');
|
||||
$floatType->serialize('one');
|
||||
}
|
||||
|
||||
public function testSerializesOutputFloatCannotRepresentEmptyString()
|
||||
{
|
||||
$floatType = Type::float();
|
||||
$this->setExpectedException(InvariantViolation::class, 'Float cannot represent non numeric value: (empty string)');
|
||||
$floatType->serialize('');
|
||||
}
|
||||
|
||||
/**
|
||||
* @it serializes output strings
|
||||
*/
|
||||
@ -145,20 +151,20 @@ class ScalarSerializationTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame('true', $stringType->serialize(true));
|
||||
$this->assertSame('false', $stringType->serialize(false));
|
||||
$this->assertSame('null', $stringType->serialize(null));
|
||||
}
|
||||
|
||||
try {
|
||||
$stringType->serialize([]);
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('String cannot represent non scalar value: array(0)', $e->getMessage());
|
||||
}
|
||||
public function testSerializesOutputStringsCannotRepresentArray()
|
||||
{
|
||||
$stringType = Type::string();
|
||||
$this->setExpectedException(InvariantViolation::class, 'String cannot represent non scalar value: array(0)');
|
||||
$stringType->serialize([]);
|
||||
}
|
||||
|
||||
try {
|
||||
$stringType->serialize(new \stdClass());
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('String cannot represent non scalar value: instance of stdClass', $e->getMessage());
|
||||
}
|
||||
public function testSerializesOutputStringsCannotRepresentObject()
|
||||
{
|
||||
$stringType = Type::string();
|
||||
$this->setExpectedException(InvariantViolation::class, 'String cannot represent non scalar value: instance of stdClass');
|
||||
$stringType->serialize(new \stdClass());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,12 +197,12 @@ class ScalarSerializationTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame('true', $idType->serialize(true));
|
||||
$this->assertSame('false', $idType->serialize(false));
|
||||
$this->assertSame('2', $idType->serialize(new ObjectIdStub(2)));
|
||||
}
|
||||
|
||||
try {
|
||||
$idType->serialize(new \stdClass());
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals('ID type cannot represent non scalar value: instance of stdClass', $e->getMessage());
|
||||
}
|
||||
public function testSerializesOutputIDCannotRepresentObject()
|
||||
{
|
||||
$idType = Type::id();
|
||||
$this->setExpectedException(InvariantViolation::class, 'ID type cannot represent non scalar value: instance of stdClass');
|
||||
$idType->serialize(new \stdClass());
|
||||
}
|
||||
}
|
||||
|
@ -1600,19 +1600,14 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
$type->assertValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* @it rejects an Enum type with incorrectly named values
|
||||
*/
|
||||
public function testRejectsAnEnumTypeWithIncorrectlyNamedValues()
|
||||
public function invalidEnumValueName()
|
||||
{
|
||||
$this->assertInvalidEnumValueName(
|
||||
'#value',
|
||||
'SomeEnum has value with invalid name: "#value" (Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "#value" does not.)'
|
||||
);
|
||||
|
||||
$this->assertInvalidEnumValueName('true', 'SomeEnum: "true" can not be used as an Enum value.');
|
||||
$this->assertInvalidEnumValueName('false', 'SomeEnum: "false" can not be used as an Enum value.');
|
||||
$this->assertInvalidEnumValueName('null', 'SomeEnum: "null" can not be used as an Enum value.');
|
||||
return [
|
||||
['#value', 'SomeEnum has value with invalid name: "#value" (Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "#value" does not.)'],
|
||||
['true', 'SomeEnum: "true" can not be used as an Enum value.'],
|
||||
['false', 'SomeEnum: "false" can not be used as an Enum value.'],
|
||||
['null', 'SomeEnum: "null" can not be used as an Enum value.'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testDoesNotAllowIsDeprecatedWithoutDeprecationReasonOnEnum()
|
||||
@ -1640,16 +1635,16 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
private function assertInvalidEnumValueName($name, $expectedMessage)
|
||||
/**
|
||||
* @it rejects an Enum type with incorrectly named values
|
||||
* @dataProvider invalidEnumValueName
|
||||
*/
|
||||
public function testRejectsAnEnumTypeWithIncorrectlyNamedValues($name, $expectedMessage)
|
||||
{
|
||||
$enum = $this->enumValue($name);
|
||||
|
||||
try {
|
||||
$enum->assertValid();
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals($expectedMessage, $e->getMessage());
|
||||
}
|
||||
$this->setExpectedException(InvariantViolation::class, $expectedMessage);
|
||||
$enum->assertValid();
|
||||
}
|
||||
|
||||
// DESCRIBE: Type System: Object fields must have output types
|
||||
@ -1898,15 +1893,8 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$schema = $this->schemaWithArgOfType(null);
|
||||
|
||||
try {
|
||||
$schema->assertValid();
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (InvariantViolation $e) {
|
||||
$this->assertEquals(
|
||||
'BadObject.badField(badArg): argument type must be Input Type but got: null',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
$this->setExpectedException(InvariantViolation::class, 'BadObject.badField(badArg): argument type must be Input Type but got: null');
|
||||
$schema->assertValid();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -42,22 +42,20 @@ class ASTFromValueTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals(new IntValueNode(['value' => '123']), AST::astFromValue(123.0, Type::int()));
|
||||
$this->assertEquals(new IntValueNode(['value' => '10000']), AST::astFromValue(1e4, Type::int()));
|
||||
$this->assertEquals(new IntValueNode(['value' => '0']), AST::astFromValue(0e4, Type::int()));
|
||||
}
|
||||
|
||||
public function testConvertsIntValuesToASTsCannotRepresentNonInteger()
|
||||
{
|
||||
// GraphQL spec does not allow coercing non-integer values to Int to avoid
|
||||
// accidental data loss.
|
||||
try {
|
||||
AST::astFromValue(123.5, Type::int());
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('Int cannot represent non-integer value: 123.5', $e->getMessage());
|
||||
}
|
||||
$this->setExpectedException(\Exception::class, 'Int cannot represent non-integer value: 123.5');
|
||||
AST::astFromValue(123.5, Type::int());
|
||||
}
|
||||
|
||||
try {
|
||||
AST::astFromValue(1e40, Type::int()); // Note: js version will produce 1e+40, both values are valid GraphQL floats
|
||||
$this->fail('Expected exception is not thrown');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertSame('Int cannot represent non 32-bit signed integer value: 1.0E+40', $e->getMessage());
|
||||
}
|
||||
public function testConvertsIntValuesToASTsCannotRepresentNon32bitsInteger()
|
||||
{
|
||||
$this->setExpectedException(\Exception::class, '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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,13 +10,7 @@ class UtilsTest extends \PHPUnit_Framework_TestCase
|
||||
$object = new \stdClass();
|
||||
$object->requiredKey = 'value';
|
||||
|
||||
try {
|
||||
Utils::assign($object, [], ['requiredKey']);
|
||||
$this->fail('Expected exception not thrown');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->assertEquals(
|
||||
"Key requiredKey is expected to be set and not to be null",
|
||||
$e->getMessage());
|
||||
}
|
||||
$this->setExpectedException(\InvalidArgumentException::class, 'Key requiredKey is expected to be set and not to be null');
|
||||
Utils::assign($object, [], ['requiredKey']);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user