mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-22 12:56:05 +03:00
Merge pull request #339 from simPod/cs-language-test
Fix CS in test/Language
This commit is contained in:
commit
a7af4663b8
@ -1,13 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GraphQL\Tests\Language;
|
||||
|
||||
use GraphQL\Error\SyntaxError;
|
||||
use GraphQL\Language\Lexer;
|
||||
use GraphQL\Language\Source;
|
||||
use GraphQL\Language\SourceLocation;
|
||||
use GraphQL\Language\Token;
|
||||
use GraphQL\Error\SyntaxError;
|
||||
use GraphQL\Utils\Utils;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function count;
|
||||
use function json_decode;
|
||||
|
||||
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')
|
||||
*/
|
||||
@ -33,7 +66,7 @@ class LexerTest extends TestCase
|
||||
'kind' => Token::NAME,
|
||||
'start' => 2,
|
||||
'end' => 5,
|
||||
'value' => 'foo'
|
||||
'value' => 'foo',
|
||||
];
|
||||
|
||||
$this->assertArraySubset($expected, (array) $this->lexOne($bom . ' foo'));
|
||||
@ -50,7 +83,7 @@ class LexerTest extends TestCase
|
||||
'end' => 11,
|
||||
'line' => 4,
|
||||
'column' => 3,
|
||||
'value' => 'foo'
|
||||
'value' => 'foo',
|
||||
];
|
||||
$this->assertArraySubset($expected, (array) $this->lexOne("\n \r\n \r foo\n"));
|
||||
}
|
||||
@ -70,7 +103,7 @@ class LexerTest extends TestCase
|
||||
'kind' => Token::NAME,
|
||||
'start' => 6,
|
||||
'end' => 9,
|
||||
'value' => 'foo'
|
||||
'value' => 'foo',
|
||||
];
|
||||
$this->assertArraySubset($expected, (array) $this->lexOne($example1));
|
||||
|
||||
@ -83,7 +116,7 @@ class LexerTest extends TestCase
|
||||
'kind' => Token::NAME,
|
||||
'start' => 18,
|
||||
'end' => 21,
|
||||
'value' => 'foo'
|
||||
'value' => 'foo',
|
||||
];
|
||||
$this->assertArraySubset($expected, (array) $this->lexOne($example2));
|
||||
|
||||
@ -91,7 +124,7 @@ class LexerTest extends TestCase
|
||||
'kind' => Token::NAME,
|
||||
'start' => 3,
|
||||
'end' => 6,
|
||||
'value' => 'foo'
|
||||
'value' => 'foo',
|
||||
];
|
||||
|
||||
$example3 = ',,,foo,,,';
|
||||
@ -181,63 +214,86 @@ class LexerTest extends TestCase
|
||||
*/
|
||||
public function testLexesStrings() : void
|
||||
{
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::STRING,
|
||||
'start' => 0,
|
||||
'end' => 8,
|
||||
'value' => 'simple'
|
||||
], (array) $this->lexOne('"simple"'));
|
||||
'value' => 'simple',
|
||||
],
|
||||
(array) $this->lexOne('"simple"')
|
||||
);
|
||||
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::STRING,
|
||||
'start' => 0,
|
||||
'end' => 15,
|
||||
'value' => ' white space '
|
||||
], (array) $this->lexOne('" white space "'));
|
||||
'value' => ' white space ',
|
||||
],
|
||||
(array) $this->lexOne('" white space "')
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::STRING,
|
||||
'start' => 0,
|
||||
'end' => 10,
|
||||
'value' => 'quote "'
|
||||
], (array) $this->lexOne('"quote \\""'));
|
||||
'value' => 'quote "',
|
||||
],
|
||||
(array) $this->lexOne('"quote \\""')
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::STRING,
|
||||
'start' => 0,
|
||||
'end' => 25,
|
||||
'value' => 'escaped \n\r\b\t\f'
|
||||
], (array) $this->lexOne('"escaped \\\\n\\\\r\\\\b\\\\t\\\\f"'));
|
||||
'value' => 'escaped \n\r\b\t\f',
|
||||
],
|
||||
(array) $this->lexOne('"escaped \\\\n\\\\r\\\\b\\\\t\\\\f"')
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::STRING,
|
||||
'start' => 0,
|
||||
'end' => 16,
|
||||
'value' => 'slashes \\ \/'
|
||||
], (array) $this->lexOne('"slashes \\\\ \\\\/"'));
|
||||
'value' => 'slashes \\ \/',
|
||||
],
|
||||
(array) $this->lexOne('"slashes \\\\ \\\\/"')
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::STRING,
|
||||
'start' => 0,
|
||||
'end' => 13,
|
||||
'value' => 'unicode яуц'
|
||||
], (array) $this->lexOne('"unicode яуц"'));
|
||||
'value' => 'unicode яуц',
|
||||
],
|
||||
(array) $this->lexOne('"unicode яуц"')
|
||||
);
|
||||
|
||||
$unicode = json_decode('"\u1234\u5678\u90AB\uCDEF"');
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::STRING,
|
||||
'start' => 0,
|
||||
'end' => 34,
|
||||
'value' => 'unicode ' . $unicode
|
||||
], (array) $this->lexOne('"unicode \u1234\u5678\u90AB\uCDEF"'));
|
||||
'value' => 'unicode ' . $unicode,
|
||||
],
|
||||
(array) $this->lexOne('"unicode \u1234\u5678\u90AB\uCDEF"')
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::STRING,
|
||||
'start' => 0,
|
||||
'end' => 26,
|
||||
'value' => $unicode
|
||||
], (array) $this->lexOne('"\u1234\u5678\u90AB\uCDEF"'));
|
||||
'value' => $unicode,
|
||||
],
|
||||
(array) $this->lexOne('"\u1234\u5678\u90AB\uCDEF"')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -245,86 +301,128 @@ class LexerTest extends TestCase
|
||||
*/
|
||||
public function testLexesBlockString() : void
|
||||
{
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::BLOCK_STRING,
|
||||
'start' => 0,
|
||||
'end' => 12,
|
||||
'value' => 'simple'
|
||||
], (array) $this->lexOne('"""simple"""'));
|
||||
'value' => 'simple',
|
||||
],
|
||||
(array) $this->lexOne('"""simple"""')
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::BLOCK_STRING,
|
||||
'start' => 0,
|
||||
'end' => 19,
|
||||
'value' => ' white space '
|
||||
], (array) $this->lexOne('""" white space """'));
|
||||
'value' => ' white space ',
|
||||
],
|
||||
(array) $this->lexOne('""" white space """')
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::BLOCK_STRING,
|
||||
'start' => 0,
|
||||
'end' => 22,
|
||||
'value' => 'contains " quote'
|
||||
], (array) $this->lexOne('"""contains " quote"""'));
|
||||
'value' => 'contains " quote',
|
||||
],
|
||||
(array) $this->lexOne('"""contains " quote"""')
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::BLOCK_STRING,
|
||||
'start' => 0,
|
||||
'end' => 31,
|
||||
'value' => 'contains """ triplequote'
|
||||
], (array) $this->lexOne('"""contains \\""" triplequote"""'));
|
||||
'value' => 'contains """ triplequote',
|
||||
],
|
||||
(array) $this->lexOne('"""contains \\""" triplequote"""')
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::BLOCK_STRING,
|
||||
'start' => 0,
|
||||
'end' => 16,
|
||||
'value' => "multi\nline"
|
||||
], (array) $this->lexOne("\"\"\"multi\nline\"\"\""));
|
||||
'value' => "multi\nline",
|
||||
],
|
||||
(array) $this->lexOne("\"\"\"multi\nline\"\"\"")
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::BLOCK_STRING,
|
||||
'start' => 0,
|
||||
'end' => 28,
|
||||
'value' => "multi\nline\nnormalized"
|
||||
], (array) $this->lexOne("\"\"\"multi\rline\r\nnormalized\"\"\""));
|
||||
'value' => "multi\nline\nnormalized",
|
||||
],
|
||||
(array) $this->lexOne("\"\"\"multi\rline\r\nnormalized\"\"\"")
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::BLOCK_STRING,
|
||||
'start' => 0,
|
||||
'end' => 32,
|
||||
'value' => 'unescaped \\n\\r\\b\\t\\f\\u1234'
|
||||
], (array) $this->lexOne('"""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"""')
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::BLOCK_STRING,
|
||||
'start' => 0,
|
||||
'end' => 19,
|
||||
'value' => 'slashes \\\\ \\/'
|
||||
], (array) $this->lexOne('"""slashes \\\\ \\/"""'));
|
||||
'value' => 'slashes \\\\ \\/',
|
||||
],
|
||||
(array) $this->lexOne('"""slashes \\\\ \\/"""')
|
||||
);
|
||||
|
||||
$this->assertArraySubset([
|
||||
$this->assertArraySubset(
|
||||
[
|
||||
'kind' => Token::BLOCK_STRING,
|
||||
'start' => 0,
|
||||
'end' => 68,
|
||||
'value' => "spans\n multiple\n lines"
|
||||
], (array) $this->lexOne("\"\"\"
|
||||
'value' => "spans\n multiple\n lines",
|
||||
],
|
||||
(array) $this->lexOne('"""
|
||||
|
||||
spans
|
||||
multiple
|
||||
lines
|
||||
|
||||
\"\"\""));
|
||||
"""')
|
||||
);
|
||||
}
|
||||
|
||||
public function reportsUsefulStringErrors() {
|
||||
public function reportsUsefulStringErrors()
|
||||
{
|
||||
return [
|
||||
['"', "Unterminated string.", $this->loc(1, 2)],
|
||||
['"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)],
|
||||
['"', 'Unterminated string.', $this->loc(1, 2)],
|
||||
['"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
|
||||
),
|
||||
],
|
||||
['"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' . "\r" . 'line"', "Unterminated string.", $this->loc(1, 7)],
|
||||
['"bad \\z esc"', "Invalid character escape sequence: \\z", $this->loc(1, 7)],
|
||||
['"multi' . "\n" . '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 \\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 \\u0XX1 esc"', "Invalid character escape sequence: \\u0XX1", $this->loc(1, 7)],
|
||||
@ -343,12 +441,27 @@ class LexerTest extends TestCase
|
||||
$this->expectSyntaxError($str, $expectedMessage, $location);
|
||||
}
|
||||
|
||||
public function reportsUsefulBlockStringErrors() {
|
||||
public function reportsUsefulBlockStringErrors()
|
||||
{
|
||||
return [
|
||||
['"""', "Unterminated string.", $this->loc(1, 4)],
|
||||
['"""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)],
|
||||
['"""', 'Unterminated string.', $this->loc(1, 4)],
|
||||
['"""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
|
||||
),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@ -435,15 +548,15 @@ class LexerTest extends TestCase
|
||||
public function reportsUsefulNumberErrors()
|
||||
{
|
||||
return [
|
||||
[ '00', "Invalid number, unexpected digit after 0: \"0\"", $this->loc(1, 2)],
|
||||
[ '+1', "Cannot parse the unexpected character \"+\".", $this->loc(1, 1)],
|
||||
[ '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)],
|
||||
[ '.123', "Cannot parse the unexpected character \".\".", $this->loc(1, 1)],
|
||||
[ '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)],
|
||||
[ '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)],
|
||||
['00', 'Invalid number, unexpected digit after 0: "0"', $this->loc(1, 2)],
|
||||
['+1', 'Cannot parse the unexpected character "+".', $this->loc(1, 1)],
|
||||
['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)],
|
||||
['.123', 'Cannot parse the unexpected character ".".', $this->loc(1, 1)],
|
||||
['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)],
|
||||
['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)],
|
||||
];
|
||||
}
|
||||
|
||||
@ -521,8 +634,8 @@ class LexerTest extends TestCase
|
||||
$unicode2 = json_decode('"\u200b"');
|
||||
|
||||
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)],
|
||||
[$unicode2, "Cannot parse the unexpected character \"\\u200b\".", $this->loc(1, 1)],
|
||||
];
|
||||
@ -544,7 +657,10 @@ class LexerTest extends TestCase
|
||||
{
|
||||
$q = 'a-b';
|
||||
$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->expectExceptionMessage('Syntax Error: Invalid number, expected digit but got: "b"');
|
||||
@ -587,42 +703,21 @@ class LexerTest extends TestCase
|
||||
$tokens[] = $tok;
|
||||
}
|
||||
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
'<SOF>',
|
||||
'{',
|
||||
'Comment',
|
||||
'Name',
|
||||
'}',
|
||||
'<EOF>'
|
||||
], Utils::map($tokens, function ($tok) {
|
||||
'<EOF>',
|
||||
],
|
||||
Utils::map(
|
||||
$tokens,
|
||||
function ($tok) {
|
||||
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
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GraphQL\Tests\Language;
|
||||
|
||||
use GraphQL\Error\InvariantViolation;
|
||||
use GraphQL\Error\SyntaxError;
|
||||
use GraphQL\Language\AST\ArgumentNode;
|
||||
use GraphQL\Language\AST\FieldNode;
|
||||
use GraphQL\Language\AST\NameNode;
|
||||
@ -13,9 +17,10 @@ use GraphQL\Language\AST\StringValueNode;
|
||||
use GraphQL\Language\Parser;
|
||||
use GraphQL\Language\Source;
|
||||
use GraphQL\Language\SourceLocation;
|
||||
use GraphQL\Error\SyntaxError;
|
||||
use GraphQL\Utils\Utils;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function file_get_contents;
|
||||
use function sprintf;
|
||||
|
||||
class ParserTest extends TestCase
|
||||
{
|
||||
@ -43,13 +48,26 @@ class ParserTest extends TestCase
|
||||
public function parseProvidesUsefulErrors()
|
||||
{
|
||||
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
|
||||
', "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",],
|
||||
['{ 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"],
|
||||
', '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",
|
||||
],
|
||||
['{ 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
|
||||
* @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 {
|
||||
Parser::parse($str);
|
||||
$this->fail('Expected exception not thrown');
|
||||
@ -114,6 +137,23 @@ fragment MissingOn Type
|
||||
);
|
||||
}
|
||||
|
||||
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"')
|
||||
*/
|
||||
@ -160,14 +200,14 @@ HEREDOC;
|
||||
'arguments' => new NodeList([
|
||||
new ArgumentNode([
|
||||
'name' => new NameNode(['value' => 'arg']),
|
||||
'value' => new StringValueNode([
|
||||
'value' => "Has a $char multi-byte character."
|
||||
])
|
||||
])
|
||||
'value' => new StringValueNode(
|
||||
['value' => sprintf('Has a %s multi-byte character.', $char)]
|
||||
),
|
||||
]),
|
||||
]),
|
||||
'directives' => new NodeList([]),
|
||||
]),
|
||||
]),
|
||||
'directives' => new NodeList([])
|
||||
])
|
||||
])
|
||||
]);
|
||||
|
||||
$this->assertEquals($expected, $result->definitions[0]->selectionSet);
|
||||
@ -196,7 +236,7 @@ HEREDOC;
|
||||
'mutation',
|
||||
'subscription',
|
||||
'true',
|
||||
'false'
|
||||
'false',
|
||||
];
|
||||
foreach ($nonKeywords as $keyword) {
|
||||
$fragmentName = $keyword;
|
||||
@ -205,14 +245,19 @@ HEREDOC;
|
||||
}
|
||||
|
||||
// Expected not to throw:
|
||||
$result = Parser::parse("query $keyword {
|
||||
$result = Parser::parse(<<<GRAPHQL
|
||||
query $keyword {
|
||||
... $fragmentName
|
||||
... on $keyword { field }
|
||||
}
|
||||
fragment $fragmentName on Type {
|
||||
$keyword($keyword: \$$keyword) @$keyword($keyword: $keyword)
|
||||
}
|
||||
");
|
||||
fragment $fragmentName on Type {
|
||||
$keyword($keyword: \$$keyword) @$keyword($keyword: $keyword)
|
||||
}
|
||||
GRAPHQL
|
||||
);
|
||||
$this->assertNotEmpty($result);
|
||||
}
|
||||
}
|
||||
@ -289,7 +334,7 @@ fragment $fragmentName on Type {
|
||||
$loc = function ($start, $end) use ($source) {
|
||||
return [
|
||||
'start' => $start,
|
||||
'end' => $end
|
||||
'end' => $end,
|
||||
];
|
||||
};
|
||||
|
||||
@ -315,7 +360,7 @@ fragment $fragmentName on Type {
|
||||
'name' => [
|
||||
'kind' => NodeKind::NAME,
|
||||
'loc' => $loc(4, 8),
|
||||
'value' => 'node'
|
||||
'value' => 'node',
|
||||
],
|
||||
'arguments' => [
|
||||
[
|
||||
@ -323,15 +368,15 @@ fragment $fragmentName on Type {
|
||||
'name' => [
|
||||
'kind' => NodeKind::NAME,
|
||||
'loc' => $loc(9, 11),
|
||||
'value' => 'id'
|
||||
'value' => 'id',
|
||||
],
|
||||
'value' => [
|
||||
'kind' => NodeKind::INT,
|
||||
'loc' => $loc(13, 14),
|
||||
'value' => '4'
|
||||
'value' => '4',
|
||||
],
|
||||
'loc' => $loc(9, 14, $source),
|
||||
],
|
||||
'loc' => $loc(9, 14, $source)
|
||||
]
|
||||
],
|
||||
'directives' => [],
|
||||
'selectionSet' => [
|
||||
@ -345,11 +390,11 @@ fragment $fragmentName on Type {
|
||||
'name' => [
|
||||
'kind' => NodeKind::NAME,
|
||||
'loc' => $loc(22, 24),
|
||||
'value' => 'id'
|
||||
'value' => 'id',
|
||||
],
|
||||
'arguments' => [],
|
||||
'directives' => [],
|
||||
'selectionSet' => null
|
||||
'selectionSet' => null,
|
||||
],
|
||||
[
|
||||
'kind' => NodeKind::FIELD,
|
||||
@ -358,22 +403,30 @@ fragment $fragmentName on Type {
|
||||
'name' => [
|
||||
'kind' => NodeKind::NAME,
|
||||
'loc' => $loc(30, 34),
|
||||
'value' => 'name'
|
||||
'value' => 'name',
|
||||
],
|
||||
'arguments' => [],
|
||||
'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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -392,7 +445,7 @@ fragment $fragmentName on Type {
|
||||
$loc = function ($start, $end) use ($source) {
|
||||
return [
|
||||
'start' => $start,
|
||||
'end' => $end
|
||||
'end' => $end,
|
||||
];
|
||||
};
|
||||
|
||||
@ -418,7 +471,7 @@ fragment $fragmentName on Type {
|
||||
'name' => [
|
||||
'kind' => NodeKind::NAME,
|
||||
'loc' => $loc(10, 14),
|
||||
'value' => 'node'
|
||||
'value' => 'node',
|
||||
],
|
||||
'arguments' => [],
|
||||
'directives' => [],
|
||||
@ -433,19 +486,19 @@ fragment $fragmentName on Type {
|
||||
'name' => [
|
||||
'kind' => NodeKind::NAME,
|
||||
'loc' => $loc(21, 23),
|
||||
'value' => 'id'
|
||||
'value' => 'id',
|
||||
],
|
||||
'arguments' => [],
|
||||
'directives' => [],
|
||||
'selectionSet' => null
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
'selectionSet' => null,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, $this->nodeToArray($result));
|
||||
@ -475,6 +528,8 @@ fragment $fragmentName on Type {
|
||||
Parser::parse($source);
|
||||
}
|
||||
|
||||
// Describe: parseValue
|
||||
|
||||
/**
|
||||
* @see it('contains location information that only stringifys start/end')
|
||||
*/
|
||||
@ -495,6 +550,8 @@ fragment $fragmentName on Type {
|
||||
$this->assertEquals($source, $result->loc->source);
|
||||
}
|
||||
|
||||
// Describe: parseType
|
||||
|
||||
/**
|
||||
* @see it('contains references to start and end tokens')
|
||||
*/
|
||||
@ -506,17 +563,18 @@ fragment $fragmentName on Type {
|
||||
$this->assertEquals('<EOF>', $result->loc->endToken->kind);
|
||||
}
|
||||
|
||||
// Describe: parseValue
|
||||
|
||||
/**
|
||||
* @see it('parses null value')
|
||||
*/
|
||||
public function testParsesNullValues() : void
|
||||
{
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
'kind' => NodeKind::NULL,
|
||||
'loc' => ['start' => 0, 'end' => 4]
|
||||
], $this->nodeToArray(Parser::parseValue('null')));
|
||||
'loc' => ['start' => 0, 'end' => 4],
|
||||
],
|
||||
$this->nodeToArray(Parser::parseValue('null'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -524,41 +582,45 @@ fragment $fragmentName on Type {
|
||||
*/
|
||||
public function testParsesListValues() : void
|
||||
{
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
'kind' => NodeKind::LST,
|
||||
'loc' => ['start' => 0, 'end' => 11],
|
||||
'values' => [
|
||||
[
|
||||
'kind' => NodeKind::INT,
|
||||
'loc' => ['start' => 1, 'end' => 4],
|
||||
'value' => '123'
|
||||
'value' => '123',
|
||||
],
|
||||
[
|
||||
'kind' => NodeKind::STRING,
|
||||
'loc' => ['start' => 5, 'end' => 10],
|
||||
'value' => 'abc',
|
||||
'block' => false
|
||||
]
|
||||
]
|
||||
], $this->nodeToArray(Parser::parseValue('[123 "abc"]')));
|
||||
'block' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
$this->nodeToArray(Parser::parseValue('[123 "abc"]'))
|
||||
);
|
||||
}
|
||||
|
||||
// Describe: parseType
|
||||
|
||||
/**
|
||||
* @see it('parses well known types')
|
||||
*/
|
||||
public function testParsesWellKnownTypes() : void
|
||||
{
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
'kind' => NodeKind::NAMED_TYPE,
|
||||
'loc' => ['start' => 0, 'end' => 6],
|
||||
'name' => [
|
||||
'kind' => NodeKind::NAME,
|
||||
'loc' => ['start' => 0, 'end' => 6],
|
||||
'value' => 'String'
|
||||
]
|
||||
], $this->nodeToArray(Parser::parseType('String')));
|
||||
'value' => 'String',
|
||||
],
|
||||
],
|
||||
$this->nodeToArray(Parser::parseType('String'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -566,15 +628,18 @@ fragment $fragmentName on Type {
|
||||
*/
|
||||
public function testParsesCustomTypes() : void
|
||||
{
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
'kind' => NodeKind::NAMED_TYPE,
|
||||
'loc' => ['start' => 0, 'end' => 6],
|
||||
'name' => [
|
||||
'kind' => NodeKind::NAME,
|
||||
'loc' => ['start' => 0, 'end' => 6],
|
||||
'value' => 'MyType'
|
||||
]
|
||||
], $this->nodeToArray(Parser::parseType('MyType')));
|
||||
'value' => 'MyType',
|
||||
],
|
||||
],
|
||||
$this->nodeToArray(Parser::parseType('MyType'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -582,7 +647,8 @@ fragment $fragmentName on Type {
|
||||
*/
|
||||
public function testParsesListTypes() : void
|
||||
{
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
'kind' => NodeKind::LIST_TYPE,
|
||||
'loc' => ['start' => 0, 'end' => 8],
|
||||
'type' => [
|
||||
@ -591,10 +657,12 @@ fragment $fragmentName on Type {
|
||||
'name' => [
|
||||
'kind' => NodeKind::NAME,
|
||||
'loc' => ['start' => 1, 'end' => 7],
|
||||
'value' => 'MyType'
|
||||
]
|
||||
]
|
||||
], $this->nodeToArray(Parser::parseType('[MyType]')));
|
||||
'value' => 'MyType',
|
||||
],
|
||||
],
|
||||
],
|
||||
$this->nodeToArray(Parser::parseType('[MyType]'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -602,7 +670,8 @@ fragment $fragmentName on Type {
|
||||
*/
|
||||
public function testParsesNonNullTypes() : void
|
||||
{
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
'kind' => NodeKind::NON_NULL_TYPE,
|
||||
'loc' => ['start' => 0, 'end' => 7],
|
||||
'type' => [
|
||||
@ -611,10 +680,12 @@ fragment $fragmentName on Type {
|
||||
'name' => [
|
||||
'kind' => NodeKind::NAME,
|
||||
'loc' => ['start' => 0, 'end' => 6],
|
||||
'value' => 'MyType'
|
||||
]
|
||||
]
|
||||
], $this->nodeToArray(Parser::parseType('MyType!')));
|
||||
'value' => 'MyType',
|
||||
],
|
||||
],
|
||||
],
|
||||
$this->nodeToArray(Parser::parseType('MyType!'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -622,7 +693,8 @@ fragment $fragmentName on Type {
|
||||
*/
|
||||
public function testParsesNestedTypes() : void
|
||||
{
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
'kind' => NodeKind::LIST_TYPE,
|
||||
'loc' => ['start' => 0, 'end' => 9],
|
||||
'type' => [
|
||||
@ -634,36 +706,12 @@ fragment $fragmentName on Type {
|
||||
'name' => [
|
||||
'kind' => NodeKind::NAME,
|
||||
'loc' => ['start' => 1, 'end' => 7],
|
||||
'value' => '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;
|
||||
}
|
||||
'value' => 'MyType',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
$this->nodeToArray(Parser::parseType('[MyType!]'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GraphQL\Tests\Language;
|
||||
|
||||
use GraphQL\Language\AST\DocumentNode;
|
||||
use GraphQL\Language\AST\EnumValueNode;
|
||||
use GraphQL\Language\AST\FieldNode;
|
||||
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\Printer;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function file_get_contents;
|
||||
|
||||
class PrinterTest extends TestCase
|
||||
{
|
||||
@ -160,7 +157,8 @@ END;
|
||||
*/
|
||||
public function testExperimentalCorrectlyPrintsFragmentDefinedVariables() : void
|
||||
{
|
||||
$fragmentWithVariable = Parser::parse('
|
||||
$fragmentWithVariable = Parser::parse(
|
||||
'
|
||||
fragment Foo($a: ComplexType, $b: Boolean = false) on TestType {
|
||||
id
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GraphQL\Tests\Language;
|
||||
|
||||
use GraphQL\Error\SyntaxError;
|
||||
@ -10,7 +13,6 @@ use PHPUnit\Framework\TestCase;
|
||||
class SchemaParserTest extends TestCase
|
||||
{
|
||||
// Describe: Schema Parser
|
||||
|
||||
/**
|
||||
* @see it('Simple type')
|
||||
*/
|
||||
@ -21,7 +23,9 @@ type Hello {
|
||||
world: String
|
||||
}';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -36,17 +40,53 @@ type Hello {
|
||||
$this->nameNode('world', $loc(16, 21)),
|
||||
$this->typeNode('String', $loc(23, 29)),
|
||||
$loc(16, 29)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(1, 31),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 31)
|
||||
],
|
||||
'loc' => $loc(0, 31),
|
||||
];
|
||||
$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')
|
||||
*/
|
||||
@ -58,7 +98,9 @@ type Hello {
|
||||
world: String
|
||||
}';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -73,18 +115,18 @@ type Hello {
|
||||
$this->nameNode('world', $loc(30, 35)),
|
||||
$this->typeNode('String', $loc(37, 43)),
|
||||
$loc(30, 43)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(1, 45),
|
||||
'description' => [
|
||||
'kind' => NodeKind::STRING,
|
||||
'value' => 'Description',
|
||||
'loc' => $loc(1, 14),
|
||||
'block' => false
|
||||
]
|
||||
]
|
||||
'block' => false,
|
||||
],
|
||||
'loc' => $loc(0, 45)
|
||||
],
|
||||
],
|
||||
'loc' => $loc(0, 45),
|
||||
];
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
}
|
||||
@ -103,7 +145,9 @@ type Hello {
|
||||
world: String
|
||||
}';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -118,18 +162,18 @@ type Hello {
|
||||
$this->nameNode('world', $loc(70, 75)),
|
||||
$this->typeNode('String', $loc(77, 83)),
|
||||
$loc(70, 83)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(1, 85),
|
||||
'description' => [
|
||||
'kind' => NodeKind::STRING,
|
||||
'value' => 'Description',
|
||||
'loc' => $loc(1, 20),
|
||||
'block' => true
|
||||
]
|
||||
]
|
||||
'block' => true,
|
||||
],
|
||||
'loc' => $loc(0, 85)
|
||||
],
|
||||
],
|
||||
'loc' => $loc(0, 85),
|
||||
];
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
}
|
||||
@ -148,6 +192,7 @@ extend type Hello {
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
'definitions' => [
|
||||
@ -161,12 +206,12 @@ extend type Hello {
|
||||
$this->nameNode('world', $loc(23, 28)),
|
||||
$this->typeNode('String', $loc(30, 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));
|
||||
}
|
||||
@ -181,6 +226,7 @@ extend type Hello {
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
'definitions' => [
|
||||
@ -192,10 +238,10 @@ extend type Hello {
|
||||
],
|
||||
'directives' => [],
|
||||
'fields' => [],
|
||||
'loc' => $loc(0, 37)
|
||||
]
|
||||
'loc' => $loc(0, 37),
|
||||
],
|
||||
'loc' => $loc(0, 37)
|
||||
],
|
||||
'loc' => $loc(0, 37),
|
||||
];
|
||||
$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')
|
||||
*/
|
||||
@ -291,10 +354,11 @@ extend type Hello {
|
||||
type Hello {
|
||||
world: String!
|
||||
}';
|
||||
$doc = Parser::parse($body);
|
||||
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
$doc = Parser::parse($body);
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -310,16 +374,16 @@ type Hello {
|
||||
[
|
||||
'kind' => NodeKind::NON_NULL_TYPE,
|
||||
'type' => $this->typeNode('String', $loc(23, 29)),
|
||||
'loc' => $loc(23, 30)
|
||||
'loc' => $loc(23, 30),
|
||||
],
|
||||
$loc(16, 30)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(1, 32),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0,32)
|
||||
],
|
||||
'loc' => $loc(0, 32),
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
@ -331,8 +395,10 @@ type Hello {
|
||||
public function testSimpleTypeInheritingInterface() : void
|
||||
{
|
||||
$body = 'type Hello implements World { field: String }';
|
||||
$loc = function($start, $end) { return TestUtils::locArray($start, $end); };
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -341,7 +407,7 @@ type Hello {
|
||||
'kind' => NodeKind::OBJECT_TYPE_DEFINITION,
|
||||
'name' => $this->nameNode('Hello', $loc(5, 10)),
|
||||
'interfaces' => [
|
||||
$this->typeNode('World', $loc(22, 27))
|
||||
$this->typeNode('World', $loc(22, 27)),
|
||||
],
|
||||
'directives' => [],
|
||||
'fields' => [
|
||||
@ -349,13 +415,13 @@ type Hello {
|
||||
$this->nameNode('field', $loc(30, 35)),
|
||||
$this->typeNode('String', $loc(37, 43)),
|
||||
$loc(30, 43)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(0, 45),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 45)
|
||||
],
|
||||
'loc' => $loc(0, 45),
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
@ -367,8 +433,10 @@ type Hello {
|
||||
public function testSimpleTypeInheritingMultipleInterfaces() : void
|
||||
{
|
||||
$body = 'type Hello implements Wo & rld { field: String }';
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -378,7 +446,7 @@ type Hello {
|
||||
'name' => $this->nameNode('Hello', $loc(5, 10)),
|
||||
'interfaces' => [
|
||||
$this->typeNode('Wo', $loc(22, 24)),
|
||||
$this->typeNode('rld', $loc(27, 30))
|
||||
$this->typeNode('rld', $loc(27, 30)),
|
||||
],
|
||||
'directives' => [],
|
||||
'fields' => [
|
||||
@ -386,13 +454,13 @@ type Hello {
|
||||
$this->nameNode('field', $loc(33, 38)),
|
||||
$this->typeNode('String', $loc(40, 46)),
|
||||
$loc(33, 46)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(0, 48),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 48)
|
||||
],
|
||||
'loc' => $loc(0, 48),
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
@ -404,8 +472,11 @@ type Hello {
|
||||
public function testSimpleTypeInheritingMultipleInterfacesWithLeadingAmpersand() : void
|
||||
{
|
||||
$body = 'type Hello implements & Wo & rld { field: String }';
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => 'Document',
|
||||
'definitions' => [
|
||||
@ -439,8 +510,10 @@ type Hello {
|
||||
public function testSingleValueEnum() : void
|
||||
{
|
||||
$body = 'enum Hello { WORLD }';
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -451,23 +524,36 @@ type Hello {
|
||||
'directives' => [],
|
||||
'values' => [$this->enumValueNode('WORLD', $loc(13, 18))],
|
||||
'loc' => $loc(0, 20),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 20)
|
||||
],
|
||||
'loc' => $loc(0, 20),
|
||||
];
|
||||
|
||||
$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')
|
||||
*/
|
||||
public function testDoubleValueEnum() : void
|
||||
{
|
||||
$body = 'enum Hello { WO, RLD }';
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -478,13 +564,13 @@ type Hello {
|
||||
'directives' => [],
|
||||
'values' => [
|
||||
$this->enumValueNode('WO', $loc(13, 15)),
|
||||
$this->enumValueNode('RLD', $loc(17, 20))
|
||||
$this->enumValueNode('RLD', $loc(17, 20)),
|
||||
],
|
||||
'loc' => $loc(0, 22),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 22)
|
||||
],
|
||||
'loc' => $loc(0, 22),
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
@ -500,7 +586,9 @@ interface Hello {
|
||||
world: String
|
||||
}';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -514,13 +602,13 @@ interface Hello {
|
||||
$this->nameNode('world', $loc(21, 26)),
|
||||
$this->typeNode('String', $loc(28, 34)),
|
||||
$loc(21, 34)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(1, 36),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0,36)
|
||||
],
|
||||
'loc' => $loc(0, 36),
|
||||
];
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
}
|
||||
@ -535,7 +623,9 @@ type Hello {
|
||||
world(flag: Boolean): String
|
||||
}';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -555,21 +645,34 @@ type Hello {
|
||||
$this->typeNode('Boolean', $loc(28, 35)),
|
||||
null,
|
||||
$loc(22, 35)
|
||||
)
|
||||
),
|
||||
],
|
||||
$loc(16, 44)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(1, 46),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 46)
|
||||
],
|
||||
'loc' => $loc(0, 46),
|
||||
];
|
||||
|
||||
$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')
|
||||
*/
|
||||
@ -580,7 +683,9 @@ type Hello {
|
||||
world(flag: Boolean = true): String
|
||||
}';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -600,16 +705,16 @@ type Hello {
|
||||
$this->typeNode('Boolean', $loc(28, 35)),
|
||||
['kind' => NodeKind::BOOLEAN, 'value' => true, 'loc' => $loc(38, 42)],
|
||||
$loc(22, 42)
|
||||
)
|
||||
),
|
||||
],
|
||||
$loc(16, 51)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(1, 53),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 53)
|
||||
],
|
||||
'loc' => $loc(0, 53),
|
||||
];
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
}
|
||||
@ -624,7 +729,9 @@ type Hello {
|
||||
world(things: [String]): String
|
||||
}';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -641,19 +748,25 @@ type Hello {
|
||||
[
|
||||
$this->inputValueNode(
|
||||
$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,
|
||||
$loc(22, 38)
|
||||
)
|
||||
),
|
||||
],
|
||||
$loc(16, 47)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(1, 49),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 49)
|
||||
],
|
||||
'loc' => $loc(0, 49),
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
@ -669,7 +782,9 @@ type Hello {
|
||||
world(argOne: Boolean, argTwo: Int): String
|
||||
}';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -695,16 +810,16 @@ type Hello {
|
||||
$this->typeNode('Int', $loc(47, 50)),
|
||||
null,
|
||||
$loc(39, 50)
|
||||
)
|
||||
),
|
||||
],
|
||||
$loc(16, 59)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(1, 61),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 61)
|
||||
],
|
||||
'loc' => $loc(0, 61),
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
@ -717,7 +832,10 @@ type Hello {
|
||||
{
|
||||
$body = 'union Hello = World';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
'definitions' => [
|
||||
@ -727,10 +845,10 @@ type Hello {
|
||||
'directives' => [],
|
||||
'types' => [$this->typeNode('World', $loc(14, 19))],
|
||||
'loc' => $loc(0, 19),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 19)
|
||||
],
|
||||
'loc' => $loc(0, 19),
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
@ -743,7 +861,9 @@ type Hello {
|
||||
{
|
||||
$body = 'union Hello = Wo | Rld';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -754,18 +874,17 @@ type Hello {
|
||||
'directives' => [],
|
||||
'types' => [
|
||||
$this->typeNode('Wo', $loc(14, 16)),
|
||||
$this->typeNode('Rld', $loc(19, 22))
|
||||
$this->typeNode('Rld', $loc(19, 22)),
|
||||
],
|
||||
'loc' => $loc(0, 22),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 22)
|
||||
],
|
||||
'loc' => $loc(0, 22),
|
||||
];
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see it('Union with two types and leading pipe')
|
||||
*/
|
||||
@ -785,8 +904,8 @@ type Hello {
|
||||
$this->typeNode('Rld', ['start' => 21, 'end' => 24]),
|
||||
],
|
||||
'loc' => ['start' => 0, 'end' => 24],
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
],
|
||||
'loc' => ['start' => 0, 'end' => 24],
|
||||
];
|
||||
@ -848,7 +967,10 @@ type Hello {
|
||||
{
|
||||
$body = 'scalar Hello';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
'definitions' => [
|
||||
@ -857,10 +979,10 @@ type Hello {
|
||||
'name' => $this->nameNode('Hello', $loc(7, 12)),
|
||||
'directives' => [],
|
||||
'loc' => $loc(0, 12),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 12)
|
||||
],
|
||||
'loc' => $loc(0, 12),
|
||||
];
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
}
|
||||
@ -875,7 +997,9 @@ input Hello {
|
||||
world: String
|
||||
}';
|
||||
$doc = Parser::parse($body);
|
||||
$loc = function($start, $end) {return TestUtils::locArray($start, $end);};
|
||||
$loc = function ($start, $end) {
|
||||
return TestUtils::locArray($start, $end);
|
||||
};
|
||||
|
||||
$expected = [
|
||||
'kind' => NodeKind::DOCUMENT,
|
||||
@ -890,13 +1014,13 @@ input Hello {
|
||||
$this->typeNode('String', $loc(24, 30)),
|
||||
null,
|
||||
$loc(17, 30)
|
||||
)
|
||||
),
|
||||
],
|
||||
'loc' => $loc(1, 32),
|
||||
'description' => null
|
||||
]
|
||||
'description' => null,
|
||||
],
|
||||
'loc' => $loc(0, 32)
|
||||
],
|
||||
'loc' => $loc(0, 32),
|
||||
];
|
||||
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
|
||||
}
|
||||
@ -980,81 +1104,4 @@ input Hello {
|
||||
];
|
||||
$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,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GraphQL\Tests;
|
||||
|
||||
use GraphQL\Language\AST\NameNode;
|
||||
@ -7,6 +10,7 @@ use GraphQL\Language\Parser;
|
||||
use GraphQL\Language\Printer;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Throwable;
|
||||
use function file_get_contents;
|
||||
|
||||
class SchemaPrinterTest extends TestCase
|
||||
{
|
||||
@ -16,7 +20,7 @@ class SchemaPrinterTest extends TestCase
|
||||
public function testPrintsMinimalAst() : void
|
||||
{
|
||||
$ast = new ScalarTypeDefinitionNode([
|
||||
'name' => new NameNode(['value' => 'foo'])
|
||||
'name' => new NameNode(['value' => 'foo']),
|
||||
]);
|
||||
$this->assertEquals('scalar foo', Printer::doPrint($ast));
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
<?php
|
||||
namespace GraphQL\Tests;
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GraphQL\Tests\Language;
|
||||
|
||||
use GraphQL\Language\AST\Location;
|
||||
use GraphQL\Language\AST\Node;
|
||||
@ -7,6 +10,13 @@ use GraphQL\Language\AST\NodeList;
|
||||
use GraphQL\Language\Parser;
|
||||
use GraphQL\Utils\AST;
|
||||
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
|
||||
{
|
||||
@ -27,33 +37,14 @@ class SerializationTest extends TestCase
|
||||
$this->assertNodesAreEqual($parsedAst, $actualAst);
|
||||
}
|
||||
|
||||
public function testSerializeSupportsNoLocationOption() : void
|
||||
{
|
||||
$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() : void
|
||||
{
|
||||
$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
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param array $path
|
||||
* @param string[] $path
|
||||
*/
|
||||
private function assertNodesAreEqual($expected, $actual, $path = [])
|
||||
private function assertNodesAreEqual(Node $expected, Node $actual, array $path = []) : void
|
||||
{
|
||||
$err = "Mismatch at AST path: " . implode(', ', $path);
|
||||
$err = 'Mismatch at AST path: ' . implode(', ', $path);
|
||||
|
||||
$this->assertInstanceOf(Node::class, $actual, $err);
|
||||
$this->assertEquals(get_class($expected), get_class($actual), $err);
|
||||
@ -67,7 +58,7 @@ class SerializationTest extends TestCase
|
||||
$actualValue = $actualVars[$name];
|
||||
$tmpPath = $path;
|
||||
$tmpPath[] = $name;
|
||||
$err = "Mismatch at AST path: " . implode(', ', $tmpPath);
|
||||
$err = 'Mismatch at AST path: ' . implode(', ', $tmpPath);
|
||||
|
||||
if ($expectedValue instanceof Node) {
|
||||
$this->assertNodesAreEqual($expectedValue, $actualValue, $tmpPath);
|
||||
@ -89,4 +80,21 @@ class SerializationTest extends TestCase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testSerializeSupportsNoLocationOption() : void
|
||||
{
|
||||
$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() : void
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,32 @@
|
||||
<?php
|
||||
namespace GraphQL\Tests\Language;
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GraphQL\Tests\Language;
|
||||
|
||||
use GraphQL\Language\AST\Location;
|
||||
use GraphQL\Language\AST\Node;
|
||||
use GraphQL\Language\AST\NodeList;
|
||||
use function get_object_vars;
|
||||
use function is_array;
|
||||
use function is_scalar;
|
||||
|
||||
class TestUtils
|
||||
{
|
||||
/**
|
||||
* @param Node $node
|
||||
* @return array
|
||||
* @return mixed[]
|
||||
*/
|
||||
public static function nodeToArray(Node $node)
|
||||
public static function nodeToArray(Node $node) : array
|
||||
{
|
||||
$result = [
|
||||
'kind' => $node->kind,
|
||||
'loc' => self::locationToArray($node->loc)
|
||||
'loc' => self::locationToArray($node->loc),
|
||||
];
|
||||
|
||||
foreach (get_object_vars($node) as $prop => $propValue) {
|
||||
if (isset($result[$prop]))
|
||||
if (isset($result[$prop])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_array($propValue) || $propValue instanceof NodeList) {
|
||||
$tmp = [];
|
||||
@ -30,7 +35,7 @@ class TestUtils
|
||||
}
|
||||
} elseif ($propValue instanceof Node) {
|
||||
$tmp = self::nodeToArray($propValue);
|
||||
} else if (is_scalar($propValue) || null === $propValue) {
|
||||
} elseif (is_scalar($propValue) || $propValue === null) {
|
||||
$tmp = $propValue;
|
||||
} else {
|
||||
$tmp = null;
|
||||
@ -38,27 +43,25 @@ class TestUtils
|
||||
|
||||
$result[$prop] = $tmp;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Location $loc
|
||||
* @return array
|
||||
* @return int[]
|
||||
*/
|
||||
public static function locationToArray(Location $loc)
|
||||
public static function locationToArray(Location $loc) : array
|
||||
{
|
||||
return [
|
||||
'start' => $loc->start,
|
||||
'end' => $loc->end
|
||||
'end' => $loc->end,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $start
|
||||
* @param $end
|
||||
* @return array
|
||||
* @return int[]
|
||||
*/
|
||||
public static function locArray($start, $end)
|
||||
public static function locArray(int $start, int $end) : array
|
||||
{
|
||||
return ['start' => $start, 'end' => $end];
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GraphQL\Tests;
|
||||
|
||||
use GraphQL\Language\Token;
|
||||
@ -13,7 +16,7 @@ class TokenTest extends TestCase
|
||||
'kind' => 'Kind',
|
||||
'value' => null,
|
||||
'line' => 3,
|
||||
'column' => 5
|
||||
'column' => 5,
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, $token->toArray());
|
||||
|
@ -29,15 +29,40 @@ use function iterator_to_array;
|
||||
|
||||
class VisitorTest extends ValidatorTestCase
|
||||
{
|
||||
private function getNodeByPath(DocumentNode $ast, $path)
|
||||
public function testValidatesPathArgument() : void
|
||||
{
|
||||
$result = $ast;
|
||||
foreach ($path as $key) {
|
||||
$resultArray = $result instanceof NodeList ? iterator_to_array($result) : $result->toArray();
|
||||
$this->assertArrayHasKey($key, $resultArray);
|
||||
$result = $resultArray[$key];
|
||||
}
|
||||
return $result;
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a }', ['noLocation' => true]);
|
||||
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
'enter' => function ($node, $key, $parent, $path) use ($ast, &$visited) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['enter', $path];
|
||||
},
|
||||
'leave' => function ($node, $key, $parent, $path) use ($ast, &$visited) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['leave', $path];
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
$expected = [
|
||||
['enter', []],
|
||||
['enter', ['definitions', 0]],
|
||||
['enter', ['definitions', 0, 'selectionSet']],
|
||||
['enter', ['definitions', 0, 'selectionSet', 'selections', 0]],
|
||||
['enter', ['definitions', 0, 'selectionSet', 'selections', 0, 'name']],
|
||||
['leave', ['definitions', 0, 'selectionSet', 'selections', 0, 'name']],
|
||||
['leave', ['definitions', 0, 'selectionSet', 'selections', 0]],
|
||||
['leave', ['definitions', 0, 'selectionSet']],
|
||||
['leave', ['definitions', 0]],
|
||||
['leave', []],
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, $visited);
|
||||
}
|
||||
|
||||
private function checkVisitorFnArgs($ast, $args, $isEdited = false)
|
||||
@ -58,6 +83,7 @@ class VisitorTest extends ValidatorTestCase
|
||||
$this->assertEquals(null, $parent);
|
||||
$this->assertEquals([], $path);
|
||||
$this->assertEquals([], $ancestors);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -84,37 +110,16 @@ class VisitorTest extends ValidatorTestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testValidatesPathArgument() : void
|
||||
private function getNodeByPath(DocumentNode $ast, $path)
|
||||
{
|
||||
$visited = [];
|
||||
$result = $ast;
|
||||
foreach ($path as $key) {
|
||||
$resultArray = $result instanceof NodeList ? iterator_to_array($result) : $result->toArray();
|
||||
$this->assertArrayHasKey($key, $resultArray);
|
||||
$result = $resultArray[$key];
|
||||
}
|
||||
|
||||
$ast = Parser::parse('{ a }', ['noLocation' => true]);
|
||||
|
||||
Visitor::visit($ast, [
|
||||
'enter' => function ($node, $key, $parent, $path) use ($ast, &$visited) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['enter', $path];
|
||||
},
|
||||
'leave' => function ($node, $key, $parent, $path) use ($ast, &$visited) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['leave', $path];
|
||||
},
|
||||
]);
|
||||
|
||||
$expected = [
|
||||
['enter', []],
|
||||
['enter', ['definitions', 0]],
|
||||
['enter', ['definitions', 0, 'selectionSet']],
|
||||
['enter', ['definitions', 0, 'selectionSet', 'selections', 0]],
|
||||
['enter', ['definitions', 0, 'selectionSet', 'selections', 0, 'name']],
|
||||
['leave', ['definitions', 0, 'selectionSet', 'selections', 0, 'name']],
|
||||
['leave', ['definitions', 0, 'selectionSet', 'selections', 0]],
|
||||
['leave', ['definitions', 0, 'selectionSet']],
|
||||
['leave', ['definitions', 0]],
|
||||
['leave', []],
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, $visited);
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function testAllowsEditingNodeOnEnterAndOnLeave() : void
|
||||
@ -122,7 +127,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
|
||||
|
||||
$selectionSet = null;
|
||||
$editedAst = Visitor::visit($ast, [
|
||||
$editedAst = Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
NodeKind::OPERATION_DEFINITION => [
|
||||
'enter' => function (OperationDefinitionNode $node) use (&$selectionSet, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
@ -133,6 +140,7 @@ class VisitorTest extends ValidatorTestCase
|
||||
'selections' => [],
|
||||
]);
|
||||
$newNode->didEnter = true;
|
||||
|
||||
return $newNode;
|
||||
},
|
||||
'leave' => function (OperationDefinitionNode $node) use (&$selectionSet, $ast) {
|
||||
@ -140,10 +148,12 @@ class VisitorTest extends ValidatorTestCase
|
||||
$newNode = clone $node;
|
||||
$newNode->selectionSet = $selectionSet;
|
||||
$newNode->didLeave = true;
|
||||
|
||||
return $newNode;
|
||||
},
|
||||
],
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertNotEquals($ast, $editedAst);
|
||||
|
||||
@ -159,13 +169,16 @@ class VisitorTest extends ValidatorTestCase
|
||||
$ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
|
||||
$definitions = $ast->definitions;
|
||||
|
||||
$editedAst = Visitor::visit($ast, [
|
||||
$editedAst = Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
NodeKind::DOCUMENT => [
|
||||
'enter' => function (DocumentNode $node) use ($ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$tmp = clone $node;
|
||||
$tmp->definitions = [];
|
||||
$tmp->didEnter = true;
|
||||
|
||||
return $tmp;
|
||||
},
|
||||
'leave' => function (DocumentNode $node) use ($definitions, $ast) {
|
||||
@ -174,7 +187,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
$node->didLeave = true;
|
||||
},
|
||||
],
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertNotEquals($ast, $editedAst);
|
||||
|
||||
@ -188,14 +202,17 @@ class VisitorTest extends ValidatorTestCase
|
||||
public function testAllowsForEditingOnEnter() : void
|
||||
{
|
||||
$ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
|
||||
$editedAst = Visitor::visit($ast, [
|
||||
$editedAst = Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
'enter' => function ($node) use ($ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
if ($node instanceof FieldNode && $node->name->value === 'b') {
|
||||
return Visitor::removeNode();
|
||||
}
|
||||
},
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]),
|
||||
@ -210,14 +227,17 @@ class VisitorTest extends ValidatorTestCase
|
||||
public function testAllowsForEditingOnLeave() : void
|
||||
{
|
||||
$ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
|
||||
$editedAst = Visitor::visit($ast, [
|
||||
$editedAst = Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
'leave' => function ($node) use ($ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args(), true);
|
||||
if ($node instanceof FieldNode && $node->name->value === 'b') {
|
||||
return Visitor::removeNode();
|
||||
}
|
||||
},
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]),
|
||||
@ -240,7 +260,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
|
||||
$ast = Parser::parse('{ a { x } }', ['noLocation' => true]);
|
||||
|
||||
Visitor::visit($ast, [
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
'enter' => function ($node) use ($addedField, &$didVisitAddedField, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args(), true);
|
||||
if ($node instanceof FieldNode && $node->name->value === 'a') {
|
||||
@ -256,7 +278,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
|
||||
$didVisitAddedField = true;
|
||||
},
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertTrue($didVisitAddedField);
|
||||
}
|
||||
@ -266,7 +289,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
$ast = Parser::parse('{ a, b { x }, c }', ['noLocation' => true]);
|
||||
|
||||
Visitor::visit($ast, [
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
'enter' => function (Node $node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['enter', $node->kind, $node->value ?? null];
|
||||
@ -278,7 +303,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['leave', $node->kind, $node->value ?? null];
|
||||
},
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
$expected = [
|
||||
['enter', 'Document', null],
|
||||
@ -306,7 +332,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
$ast = Parser::parse('{ a, b { x }, c }', ['noLocation' => true]);
|
||||
|
||||
Visitor::visit($ast, [
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
'enter' => function (Node $node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['enter', $node->kind, $node->value ?? null];
|
||||
@ -318,7 +346,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['leave', $node->kind, $node->value ?? null];
|
||||
},
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
$expected = [
|
||||
['enter', 'Document', null],
|
||||
@ -344,7 +373,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a, b { x }, c }', ['noLocation' => true]);
|
||||
Visitor::visit($ast, [
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
'enter' => function ($node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['enter', $node->kind, $node->value ?? null];
|
||||
@ -357,9 +388,12 @@ class VisitorTest extends ValidatorTestCase
|
||||
return Visitor::stop();
|
||||
}
|
||||
},
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals($visited, [
|
||||
$this->assertEquals(
|
||||
$visited,
|
||||
[
|
||||
['enter', 'Document', null],
|
||||
['enter', 'OperationDefinition', null],
|
||||
['enter', 'SelectionSet', null],
|
||||
@ -374,7 +408,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'x'],
|
||||
['leave', 'Name', 'x'],
|
||||
]);
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function testAllowsANamedFunctionsVisitorAPI() : void
|
||||
@ -382,7 +417,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
$ast = Parser::parse('{ a, b { x }, c }', ['noLocation' => true]);
|
||||
|
||||
Visitor::visit($ast, [
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
NodeKind::NAME => function (NameNode $node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['enter', $node->kind, $node->value];
|
||||
@ -397,7 +434,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited[] = ['leave', $node->kind, null];
|
||||
},
|
||||
],
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
$expected = [
|
||||
['enter', 'SelectionSet', null],
|
||||
@ -424,7 +462,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
);
|
||||
$visited = [];
|
||||
|
||||
Visitor::visit($ast, [
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
'enter' => function ($node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['enter', $node->kind, $node->value ?? null];
|
||||
@ -433,7 +473,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['leave', $node->kind, $node->value ?? null];
|
||||
},
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
$expected = [
|
||||
['enter', 'Document', null],
|
||||
@ -475,7 +516,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$ast = Parser::parse($kitchenSink);
|
||||
|
||||
$visited = [];
|
||||
Visitor::visit($ast, [
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
[
|
||||
'enter' => function (Node $node, $key, $parent) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$r = ['enter', $node->kind, $key, $parent instanceof Node ? $parent->kind : null];
|
||||
@ -486,7 +529,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
$r = ['leave', $node->kind, $key, $parent instanceof Node ? $parent->kind : null];
|
||||
$visited[] = $r;
|
||||
},
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
$expected = [
|
||||
['enter', 'Document', null, null],
|
||||
@ -813,7 +857,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a, b { x }, c }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
Visitor::visitInParallel([
|
||||
[
|
||||
'enter' => function ($node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
@ -829,9 +875,11 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited[] = ['leave', $node->kind, $node->value ?? null];
|
||||
},
|
||||
],
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
['enter', 'Document', null],
|
||||
['enter', 'OperationDefinition', null],
|
||||
['enter', 'SelectionSet', null],
|
||||
@ -847,7 +895,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
['leave', 'SelectionSet', null],
|
||||
['leave', 'OperationDefinition', null],
|
||||
['leave', 'Document', null],
|
||||
], $visited);
|
||||
],
|
||||
$visited
|
||||
);
|
||||
}
|
||||
|
||||
public function testAllowsSkippingDifferentSubTrees() : void
|
||||
@ -855,7 +905,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a { x }, b { y} }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
Visitor::visitInParallel([
|
||||
[
|
||||
'enter' => function ($node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
@ -882,9 +934,11 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited[] = ['no-b', 'leave', $node->kind, $node->value ?? null];
|
||||
},
|
||||
],
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
['no-a', 'enter', 'Document', null],
|
||||
['no-b', 'enter', 'Document', null],
|
||||
['no-a', 'enter', 'OperationDefinition', null],
|
||||
@ -919,7 +973,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
['no-b', 'leave', 'OperationDefinition', null],
|
||||
['no-a', 'leave', 'Document', null],
|
||||
['no-b', 'leave', 'Document', null],
|
||||
], $visited);
|
||||
],
|
||||
$visited
|
||||
);
|
||||
}
|
||||
|
||||
public function testAllowsEarlyExitWhileVisiting2() : void
|
||||
@ -927,7 +983,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a, b { x }, c }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([ [
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
Visitor::visitInParallel([[
|
||||
'enter' => function ($node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$value = $node->value ?? null;
|
||||
@ -941,9 +999,11 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited[] = ['leave', $node->kind, $node->value ?? null];
|
||||
},
|
||||
],
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
['enter', 'Document', null],
|
||||
['enter', 'OperationDefinition', null],
|
||||
['enter', 'SelectionSet', null],
|
||||
@ -957,7 +1017,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
['enter', 'SelectionSet', null],
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'x'],
|
||||
], $visited);
|
||||
],
|
||||
$visited
|
||||
);
|
||||
}
|
||||
|
||||
public function testAllowsEarlyExitFromDifferentPoints() : void
|
||||
@ -965,7 +1027,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a { y }, b { x } }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
Visitor::visitInParallel([
|
||||
[
|
||||
'enter' => function ($node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
@ -994,9 +1058,11 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited[] = ['break-b', 'leave', $node->kind, $node->value ?? null];
|
||||
},
|
||||
],
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
['break-a', 'enter', 'Document', null],
|
||||
['break-b', 'enter', 'Document', null],
|
||||
['break-a', 'enter', 'OperationDefinition', null],
|
||||
@ -1017,7 +1083,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
['break-b', 'leave', 'Field', null],
|
||||
['break-b', 'enter', 'Field', null],
|
||||
['break-b', 'enter', 'Name', 'b'],
|
||||
], $visited);
|
||||
],
|
||||
$visited
|
||||
);
|
||||
}
|
||||
|
||||
public function testAllowsEarlyExitWhileLeaving2() : void
|
||||
@ -1025,7 +1093,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a, b { x }, c }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([ [
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
Visitor::visitInParallel([[
|
||||
'enter' => function ($node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$visited[] = ['enter', $node->kind, $node->value ?? null];
|
||||
@ -1039,9 +1109,11 @@ class VisitorTest extends ValidatorTestCase
|
||||
}
|
||||
},
|
||||
],
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
['enter', 'Document', null],
|
||||
['enter', 'OperationDefinition', null],
|
||||
['enter', 'SelectionSet', null],
|
||||
@ -1056,7 +1128,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'x'],
|
||||
['leave', 'Name', 'x'],
|
||||
], $visited);
|
||||
],
|
||||
$visited
|
||||
);
|
||||
}
|
||||
|
||||
public function testAllowsEarlyExitFromLeavingDifferentPoints() : void
|
||||
@ -1064,7 +1138,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a { y }, b { x } }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
Visitor::visitInParallel([
|
||||
[
|
||||
'enter' => function ($node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
@ -1091,9 +1167,11 @@ class VisitorTest extends ValidatorTestCase
|
||||
}
|
||||
},
|
||||
],
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
['break-a', 'enter', 'Document', null],
|
||||
['break-b', 'enter', 'Document', null],
|
||||
['break-a', 'enter', 'OperationDefinition', null],
|
||||
@ -1130,7 +1208,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
['break-b', 'leave', 'Field', null],
|
||||
['break-b', 'leave', 'SelectionSet', null],
|
||||
['break-b', 'leave', 'Field', null],
|
||||
], $visited);
|
||||
],
|
||||
$visited
|
||||
);
|
||||
}
|
||||
|
||||
public function testAllowsForEditingOnEnter2() : void
|
||||
@ -1138,7 +1218,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
|
||||
$editedAst = Visitor::visit($ast, Visitor::visitInParallel([
|
||||
$editedAst = Visitor::visit(
|
||||
$ast,
|
||||
Visitor::visitInParallel([
|
||||
[
|
||||
'enter' => function ($node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
@ -1157,7 +1239,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited[] = ['leave', $node->kind, $node->value ?? null];
|
||||
},
|
||||
],
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]),
|
||||
@ -1169,7 +1252,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
$editedAst
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
['enter', 'Document', null],
|
||||
['enter', 'OperationDefinition', null],
|
||||
['enter', 'SelectionSet', null],
|
||||
@ -1194,7 +1278,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
['leave', 'SelectionSet', null],
|
||||
['leave', 'OperationDefinition', null],
|
||||
['leave', 'Document', null],
|
||||
], $visited);
|
||||
],
|
||||
$visited
|
||||
);
|
||||
}
|
||||
|
||||
public function testAllowsForEditingOnLeave2() : void
|
||||
@ -1202,7 +1288,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
|
||||
$editedAst = Visitor::visit($ast, Visitor::visitInParallel([
|
||||
$editedAst = Visitor::visit(
|
||||
$ast,
|
||||
Visitor::visitInParallel([
|
||||
[
|
||||
'leave' => function ($node) use (&$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args(), true);
|
||||
@ -1221,7 +1309,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
$visited[] = ['leave', $node->kind, $node->value ?? null];
|
||||
},
|
||||
],
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]),
|
||||
@ -1233,7 +1322,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
$editedAst
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
['enter', 'Document', null],
|
||||
['enter', 'OperationDefinition', null],
|
||||
['enter', 'SelectionSet', null],
|
||||
@ -1264,10 +1354,11 @@ class VisitorTest extends ValidatorTestCase
|
||||
['leave', 'SelectionSet', null],
|
||||
['leave', 'OperationDefinition', null],
|
||||
['leave', 'Document', null],
|
||||
], $visited);
|
||||
],
|
||||
$visited
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describe: visitWithTypeInfo
|
||||
*/
|
||||
@ -1278,7 +1369,11 @@ class VisitorTest extends ValidatorTestCase
|
||||
$typeInfo = new TypeInfo(ValidatorTestCase::getTestSchema());
|
||||
|
||||
$ast = Parser::parse('{ human(id: 4) { name, pets { ... { name } }, unknown } }');
|
||||
Visitor::visit($ast, Visitor::visitWithTypeInfo($typeInfo, [
|
||||
Visitor::visit(
|
||||
$ast,
|
||||
Visitor::visitWithTypeInfo(
|
||||
$typeInfo,
|
||||
[
|
||||
'enter' => function ($node) use ($typeInfo, &$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args());
|
||||
$parentType = $typeInfo->getParentType();
|
||||
@ -1307,9 +1402,12 @@ class VisitorTest extends ValidatorTestCase
|
||||
$inputType ? (string) $inputType : null,
|
||||
];
|
||||
},
|
||||
]));
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
['enter', 'Document', null, null, null, null],
|
||||
['enter', 'OperationDefinition', null, null, 'QueryRoot', null],
|
||||
['enter', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],
|
||||
@ -1350,7 +1448,9 @@ class VisitorTest extends ValidatorTestCase
|
||||
['leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],
|
||||
['leave', 'OperationDefinition', null, null, 'QueryRoot', null],
|
||||
['leave', 'Document', null, null, null, null],
|
||||
], $visited);
|
||||
],
|
||||
$visited
|
||||
);
|
||||
}
|
||||
|
||||
public function testMaintainsTypeInfoDuringEdit() : void
|
||||
@ -1361,7 +1461,11 @@ class VisitorTest extends ValidatorTestCase
|
||||
$ast = Parser::parse(
|
||||
'{ human(id: 4) { name, pets }, alien }'
|
||||
);
|
||||
$editedAst = Visitor::visit($ast, Visitor::visitWithTypeInfo($typeInfo, [
|
||||
$editedAst = Visitor::visit(
|
||||
$ast,
|
||||
Visitor::visitWithTypeInfo(
|
||||
$typeInfo,
|
||||
[
|
||||
'enter' => function ($node) use ($typeInfo, &$visited, $ast) {
|
||||
$this->checkVisitorFnArgs($ast, func_get_args(), true);
|
||||
$parentType = $typeInfo->getParentType();
|
||||
@ -1410,17 +1514,26 @@ class VisitorTest extends ValidatorTestCase
|
||||
$inputType ? (string) $inputType : null,
|
||||
];
|
||||
},
|
||||
]));
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertEquals(Printer::doPrint(Parser::parse(
|
||||
$this->assertEquals(
|
||||
Printer::doPrint(Parser::parse(
|
||||
'{ human(id: 4) { name, pets }, alien }'
|
||||
)), Printer::doPrint($ast));
|
||||
)),
|
||||
Printer::doPrint($ast)
|
||||
);
|
||||
|
||||
$this->assertEquals(Printer::doPrint(Parser::parse(
|
||||
$this->assertEquals(
|
||||
Printer::doPrint(Parser::parse(
|
||||
'{ human(id: 4) { name, pets { __typename } }, alien { __typename } }'
|
||||
)), Printer::doPrint($editedAst));
|
||||
)),
|
||||
Printer::doPrint($editedAst)
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
$this->assertEquals(
|
||||
[
|
||||
['enter', 'Document', null, null, null, null],
|
||||
['enter', 'OperationDefinition', null, null, 'QueryRoot', null],
|
||||
['enter', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],
|
||||
@ -1463,6 +1576,8 @@ class VisitorTest extends ValidatorTestCase
|
||||
['leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],
|
||||
['leave', 'OperationDefinition', null, null, 'QueryRoot', null],
|
||||
['leave', 'Document', null, null, null, null],
|
||||
], $visited);
|
||||
],
|
||||
$visited
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user