Fix CS in test/Language

This commit is contained in:
Simon Podlipsky 2018-09-01 20:21:08 +02:00
parent ec54d6152b
commit d1f49bedbd
No known key found for this signature in database
GPG Key ID: 725C2BD962B42663
9 changed files with 2157 additions and 1836 deletions

View File

@ -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,15 +657,18 @@ 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"');
try {
$lexer->advance();
$this->fail('Expected exception not thrown');
} catch(SyntaxError $error) {
$this->assertEquals([$this->loc(1,3)], $error->getLocations());
} catch (SyntaxError $error) {
$this->assertEquals([$this->loc(1, 3)], $error->getLocations());
throw $error;
}
}
@ -580,49 +696,28 @@ class LexerTest extends TestCase
$tokens = [];
for ($tok = $startToken; $tok; $tok = $tok->next) {
if (!empty($tokens)) {
if (! empty($tokens)) {
// Tokens are double-linked, prev should point to last seen token.
$this->assertSame($tokens[count($tokens) - 1], $tok->prev);
}
$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;
}
)
);
}
}

View File

@ -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');
@ -110,10 +133,27 @@ fragment MissingOn Type
$this->expectSyntaxError(
'query Foo($x: Complex = { a: { b: [ $var ] } }) { field }',
'Unexpected $',
$this->loc(1,37)
$this->loc(1, 37)
);
}
private function expectSyntaxError($text, $message, $location)
{
$this->expectException(SyntaxError::class);
$this->expectExceptionMessage($message);
try {
Parser::parse($text);
} catch (SyntaxError $error) {
$this->assertEquals([$location], $error->getLocations());
throw $error;
}
}
private function loc($line, $column)
{
return new SourceLocation($line, $column);
}
/**
* @see it('does not accept fragments spread of "on"')
*/
@ -122,7 +162,7 @@ fragment MissingOn Type
$this->expectSyntaxError(
'fragment on on on { on }',
'Unexpected Name "on"',
$this->loc(1,10)
$this->loc(1, 10)
);
}
@ -134,7 +174,7 @@ fragment MissingOn Type
$this->expectSyntaxError(
'{ ...on }',
'Expected Name, found }',
$this->loc(1,9)
$this->loc(1, 9)
);
}
@ -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 {
... $fragmentName
... on $keyword { field }
$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);
}
}
@ -286,10 +331,10 @@ fragment $fragmentName on Type {
');
$result = Parser::parse($source);
$loc = function($start, $end) use ($source) {
$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);
}
/**
@ -389,10 +442,10 @@ fragment $fragmentName on Type {
');
$result = Parser::parse($source);
$loc = function($start, $end) use ($source) {
$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!]'))
);
}
}

View File

@ -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
}

View File

@ -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));
}
@ -145,9 +189,10 @@ extend type Hello {
}
';
$doc = Parser::parse($body);
$loc = function($start, $end) {
$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));
}
@ -178,9 +223,10 @@ extend type Hello {
{
$body = 'extend type Hello implements Greeting';
$doc = Parser::parse($body);
$loc = function($start, $end) {
$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,17 +354,18 @@ extend type Hello {
type Hello {
world: String!
}';
$loc = function($start, $end) {
$doc = Parser::parse($body);
$loc = function ($start, $end) {
return TestUtils::locArray($start, $end);
};
$doc = Parser::parse($body);
$expected = [
'kind' => NodeKind::DOCUMENT,
'definitions' => [
[
'kind' => NodeKind::OBJECT_TYPE_DEFINITION,
'name' => $this->nameNode('Hello', $loc(6,11)),
'name' => $this->nameNode('Hello', $loc(6, 11)),
'interfaces' => [],
'directives' => [],
'fields' => [
@ -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(16, 30)
),
],
'loc' => $loc(1,32),
'description' => null
]
'loc' => $loc(1, 32),
'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,
@ -640,20 +747,26 @@ type Hello {
$this->typeNode('String', $loc(41, 47)),
[
$this->inputValueNode(
$this->nameNode('things', $loc(22,28)),
['kind' => NodeKind::LIST_TYPE, 'type' => $this->typeNode('String', $loc(31, 37)), 'loc' => $loc(30, 38)],
$this->nameNode('things', $loc(22, 28)),
[
'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;
}
}
}

View File

@ -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));
}

View File

@ -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,6 +37,50 @@ class SerializationTest extends TestCase
$this->assertNodesAreEqual($parsedAst, $actualAst);
}
/**
* Compares two nodes by actually iterating over all NodeLists, properly comparing locations (ignoring tokens), etc
*
* @param string[] $path
*/
private function assertNodesAreEqual(Node $expected, Node $actual, array $path = []) : void
{
$err = 'Mismatch at AST path: ' . implode(', ', $path);
$this->assertInstanceOf(Node::class, $actual, $err);
$this->assertEquals(get_class($expected), get_class($actual), $err);
$expectedVars = get_object_vars($expected);
$actualVars = get_object_vars($actual);
$this->assertSame(count($expectedVars), count($actualVars), $err);
$this->assertEquals(array_keys($expectedVars), array_keys($actualVars), $err);
foreach ($expectedVars as $name => $expectedValue) {
$actualValue = $actualVars[$name];
$tmpPath = $path;
$tmpPath[] = $name;
$err = 'Mismatch at AST path: ' . implode(', ', $tmpPath);
if ($expectedValue instanceof Node) {
$this->assertNodesAreEqual($expectedValue, $actualValue, $tmpPath);
} elseif ($expectedValue instanceof NodeList) {
$this->assertEquals(count($expectedValue), count($actualValue), $err);
$this->assertInstanceOf(NodeList::class, $actualValue, $err);
foreach ($expectedValue as $index => $listNode) {
$tmpPath2 = $tmpPath;
$tmpPath2[] = $index;
$this->assertNodesAreEqual($listNode, $actualValue[$index], $tmpPath2);
}
} elseif ($expectedValue instanceof Location) {
$this->assertInstanceOf(Location::class, $actualValue, $err);
$this->assertSame($expectedValue->start, $actualValue->start, $err);
$this->assertSame($expectedValue->end, $actualValue->end, $err);
} else {
$this->assertEquals($expectedValue, $actualValue, $err);
}
}
}
public function testSerializeSupportsNoLocationOption() : void
{
$kitchenSink = file_get_contents(__DIR__ . '/kitchen-sink.graphql');
@ -43,50 +97,4 @@ class SerializationTest extends TestCase
$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
*/
private function assertNodesAreEqual($expected, $actual, $path = [])
{
$err = "Mismatch at AST path: " . implode(', ', $path);
$this->assertInstanceOf(Node::class, $actual, $err);
$this->assertEquals(get_class($expected), get_class($actual), $err);
$expectedVars = get_object_vars($expected);
$actualVars = get_object_vars($actual);
$this->assertSame(count($expectedVars), count($actualVars), $err);
$this->assertEquals(array_keys($expectedVars), array_keys($actualVars), $err);
foreach ($expectedVars as $name => $expectedValue) {
$actualValue = $actualVars[$name];
$tmpPath = $path;
$tmpPath[] = $name;
$err = "Mismatch at AST path: " . implode(', ', $tmpPath);
if ($expectedValue instanceof Node) {
$this->assertNodesAreEqual($expectedValue, $actualValue, $tmpPath);
} else if ($expectedValue instanceof NodeList) {
$this->assertEquals(count($expectedValue), count($actualValue), $err);
$this->assertInstanceOf(NodeList::class, $actualValue, $err);
foreach ($expectedValue as $index => $listNode) {
$tmpPath2 = $tmpPath;
$tmpPath2 [] = $index;
$this->assertNodesAreEqual($listNode, $actualValue[$index], $tmpPath2);
}
} else if ($expectedValue instanceof Location) {
$this->assertInstanceOf(Location::class, $actualValue, $err);
$this->assertSame($expectedValue->start, $actualValue->start, $err);
$this->assertSame($expectedValue->end, $actualValue->end, $err);
} else {
$this->assertEquals($expectedValue, $actualValue, $err);
}
}
}
}

View File

@ -1,36 +1,41 @@
<?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 = [];
foreach ($propValue as $tmp1) {
$tmp[] = $tmp1 instanceof Node ? self::nodeToArray($tmp1) : (array) $tmp1;
}
} else if ($propValue instanceof Node) {
} 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];
}

View File

@ -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());

File diff suppressed because it is too large Load Diff