mirror of
https://github.com/retailcrm/graphql-php.git
synced 2025-02-06 07:49:24 +03:00
Fixed visitor; more visitor tests
This commit is contained in:
parent
71924f1154
commit
e82f887918
@ -256,7 +256,9 @@ class Visitor
|
||||
array_pop($path);
|
||||
continue;
|
||||
}
|
||||
$editValue = null;
|
||||
if ($result->removeNode) {
|
||||
$editValue = null;
|
||||
}
|
||||
} else {
|
||||
$editValue = $result;
|
||||
}
|
||||
@ -312,7 +314,6 @@ class Visitor
|
||||
*/
|
||||
static function visitInParallel($visitors)
|
||||
{
|
||||
// TODO: implement real parallel visiting once PHP supports it
|
||||
$visitorsCount = count($visitors);
|
||||
$skipping = new \SplFixedArray($visitorsCount);
|
||||
|
||||
@ -330,6 +331,8 @@ class Visitor
|
||||
$skipping[$i] = $node;
|
||||
} else if ($result->doBreak) {
|
||||
$skipping[$i] = $result;
|
||||
} else if ($result->removeNode) {
|
||||
return $result;
|
||||
}
|
||||
} else if ($result !== null) {
|
||||
return $result;
|
||||
@ -348,6 +351,8 @@ class Visitor
|
||||
if ($result instanceof VisitorOperation) {
|
||||
if ($result->doBreak) {
|
||||
$skipping[$i] = $result;
|
||||
} else if ($result->removeNode) {
|
||||
return $result;
|
||||
}
|
||||
} else if ($result !== null) {
|
||||
return $result;
|
||||
|
@ -8,7 +8,11 @@ use GraphQL\Language\AST\Node;
|
||||
use GraphQL\Language\AST\OperationDefinition;
|
||||
use GraphQL\Language\AST\SelectionSet;
|
||||
use GraphQL\Language\Parser;
|
||||
use GraphQL\Language\Printer;
|
||||
use GraphQL\Language\Visitor;
|
||||
use GraphQL\Tests\Validator\TestCase;
|
||||
use GraphQL\Type\Definition\Type;
|
||||
use GraphQL\Utils\TypeInfo;
|
||||
|
||||
class VisitorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
@ -643,4 +647,661 @@ class VisitorTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertEquals($expected, $visited);
|
||||
}
|
||||
|
||||
// Describe: visitInParallel
|
||||
// Note: nearly identical to the above test of the same test but using visitInParallel.
|
||||
|
||||
/**
|
||||
* @it allows skipping a sub-tree
|
||||
*/
|
||||
public function testAllowsSkippingSubTree()
|
||||
{
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a, b { x }, c }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([
|
||||
[
|
||||
'enter' => function($node) use (&$visited) {
|
||||
$visited[] = [ 'enter', $node->kind, isset($node->value) ? $node->value : null];
|
||||
|
||||
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'b') {
|
||||
return Visitor::skipNode();
|
||||
}
|
||||
},
|
||||
|
||||
'leave' => function($node) use (&$visited) {
|
||||
$visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
|
||||
}
|
||||
]
|
||||
]));
|
||||
|
||||
$this->assertEquals([
|
||||
[ 'enter', 'Document', null ],
|
||||
[ 'enter', 'OperationDefinition', null ],
|
||||
[ 'enter', 'SelectionSet', null ],
|
||||
[ 'enter', 'Field', null ],
|
||||
[ 'enter', 'Name', 'a' ],
|
||||
[ 'leave', 'Name', 'a' ],
|
||||
[ 'leave', 'Field', null ],
|
||||
[ 'enter', 'Field', null ],
|
||||
[ 'enter', 'Field', null ],
|
||||
[ 'enter', 'Name', 'c' ],
|
||||
[ 'leave', 'Name', 'c' ],
|
||||
[ 'leave', 'Field', null ],
|
||||
[ 'leave', 'SelectionSet', null ],
|
||||
[ 'leave', 'OperationDefinition', null ],
|
||||
[ 'leave', 'Document', null ],
|
||||
], $visited);
|
||||
}
|
||||
|
||||
/**
|
||||
* @it allows skipping different sub-trees
|
||||
*/
|
||||
public function testAllowsSkippingDifferentSubTrees()
|
||||
{
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a { x }, b { y} }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([
|
||||
[
|
||||
'enter' => function($node) use (&$visited) {
|
||||
$visited[] = ['no-a', 'enter', $node->kind, isset($node->value) ? $node->value : null];
|
||||
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'a') {
|
||||
return Visitor::skipNode();
|
||||
}
|
||||
},
|
||||
'leave' => function($node) use (&$visited) {
|
||||
$visited[] = [ 'no-a', 'leave', $node->kind, isset($node->value) ? $node->value : null ];
|
||||
}
|
||||
],
|
||||
[
|
||||
'enter' => function($node) use (&$visited) {
|
||||
$visited[] = ['no-b', 'enter', $node->kind, isset($node->value) ? $node->value : null];
|
||||
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'b') {
|
||||
return Visitor::skipNode();
|
||||
}
|
||||
},
|
||||
'leave' => function($node) use (&$visited) {
|
||||
$visited[] = ['no-b', 'leave', $node->kind, isset($node->value) ? $node->value : null];
|
||||
}
|
||||
]
|
||||
]));
|
||||
|
||||
$this->assertEquals([
|
||||
[ 'no-a', 'enter', 'Document', null ],
|
||||
[ 'no-b', 'enter', 'Document', null ],
|
||||
[ 'no-a', 'enter', 'OperationDefinition', null ],
|
||||
[ 'no-b', 'enter', 'OperationDefinition', null ],
|
||||
[ 'no-a', 'enter', 'SelectionSet', null ],
|
||||
[ 'no-b', 'enter', 'SelectionSet', null ],
|
||||
[ 'no-a', 'enter', 'Field', null ],
|
||||
[ 'no-b', 'enter', 'Field', null ],
|
||||
[ 'no-b', 'enter', 'Name', 'a' ],
|
||||
[ 'no-b', 'leave', 'Name', 'a' ],
|
||||
[ 'no-b', 'enter', 'SelectionSet', null ],
|
||||
[ 'no-b', 'enter', 'Field', null ],
|
||||
[ 'no-b', 'enter', 'Name', 'x' ],
|
||||
[ 'no-b', 'leave', 'Name', 'x' ],
|
||||
[ 'no-b', 'leave', 'Field', null ],
|
||||
[ 'no-b', 'leave', 'SelectionSet', null ],
|
||||
[ 'no-b', 'leave', 'Field', null ],
|
||||
[ 'no-a', 'enter', 'Field', null ],
|
||||
[ 'no-b', 'enter', 'Field', null ],
|
||||
[ 'no-a', 'enter', 'Name', 'b' ],
|
||||
[ 'no-a', 'leave', 'Name', 'b' ],
|
||||
[ 'no-a', 'enter', 'SelectionSet', null ],
|
||||
[ 'no-a', 'enter', 'Field', null ],
|
||||
[ 'no-a', 'enter', 'Name', 'y' ],
|
||||
[ 'no-a', 'leave', 'Name', 'y' ],
|
||||
[ 'no-a', 'leave', 'Field', null ],
|
||||
[ 'no-a', 'leave', 'SelectionSet', null ],
|
||||
[ 'no-a', 'leave', 'Field', null ],
|
||||
[ 'no-a', 'leave', 'SelectionSet', null ],
|
||||
[ 'no-b', 'leave', 'SelectionSet', null ],
|
||||
[ 'no-a', 'leave', 'OperationDefinition', null ],
|
||||
[ 'no-b', 'leave', 'OperationDefinition', null ],
|
||||
[ 'no-a', 'leave', 'Document', null ],
|
||||
[ 'no-b', 'leave', 'Document', null ],
|
||||
], $visited);
|
||||
}
|
||||
|
||||
/**
|
||||
* @it allows early exit while visiting
|
||||
*/
|
||||
public function testAllowsEarlyExitWhileVisiting2()
|
||||
{
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a, b { x }, c }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([ [
|
||||
'enter' => function($node) use (&$visited) {
|
||||
$value = isset($node->value) ? $node->value : null;
|
||||
$visited[] = ['enter', $node->kind, $value];
|
||||
if ($node->kind === 'Name' && $value === 'x') {
|
||||
return Visitor::stop();
|
||||
}
|
||||
},
|
||||
'leave' => function($node) use (&$visited) {
|
||||
$visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
|
||||
}
|
||||
] ]));
|
||||
|
||||
$this->assertEquals([
|
||||
[ 'enter', 'Document', null ],
|
||||
[ 'enter', 'OperationDefinition', null ],
|
||||
[ 'enter', 'SelectionSet', null ],
|
||||
[ 'enter', 'Field', null ],
|
||||
[ 'enter', 'Name', 'a' ],
|
||||
[ 'leave', 'Name', 'a' ],
|
||||
[ 'leave', 'Field', null ],
|
||||
[ 'enter', 'Field', null ],
|
||||
[ 'enter', 'Name', 'b' ],
|
||||
[ 'leave', 'Name', 'b' ],
|
||||
[ 'enter', 'SelectionSet', null ],
|
||||
[ 'enter', 'Field', null ],
|
||||
[ 'enter', 'Name', 'x' ]
|
||||
], $visited);
|
||||
}
|
||||
|
||||
/**
|
||||
* @it allows early exit from different points
|
||||
*/
|
||||
public function testAllowsEarlyExitFromDifferentPoints()
|
||||
{
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a { y }, b { x } }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([
|
||||
[
|
||||
'enter' => function($node) use (&$visited) {
|
||||
$value = isset($node->value) ? $node->value : null;
|
||||
$visited[] = ['break-a', 'enter', $node->kind, $value];
|
||||
if ($node->kind === 'Name' && $value === 'a') {
|
||||
return Visitor::stop();
|
||||
}
|
||||
},
|
||||
'leave' => function($node) use (&$visited) {
|
||||
$visited[] = [ 'break-a', 'leave', $node->kind, isset($node->value) ? $node->value : null ];
|
||||
}
|
||||
],
|
||||
[
|
||||
'enter' => function($node) use (&$visited) {
|
||||
$value = isset($node->value) ? $node->value : null;
|
||||
$visited[] = ['break-b', 'enter', $node->kind, $value];
|
||||
if ($node->kind === 'Name' && $value === 'b') {
|
||||
return Visitor::stop();
|
||||
}
|
||||
},
|
||||
'leave' => function($node) use (&$visited) {
|
||||
$visited[] = ['break-b', 'leave', $node->kind, isset($node->value) ? $node->value : null];
|
||||
}
|
||||
],
|
||||
]));
|
||||
|
||||
$this->assertEquals([
|
||||
[ 'break-a', 'enter', 'Document', null ],
|
||||
[ 'break-b', 'enter', 'Document', null ],
|
||||
[ 'break-a', 'enter', 'OperationDefinition', null ],
|
||||
[ 'break-b', 'enter', 'OperationDefinition', null ],
|
||||
[ 'break-a', 'enter', 'SelectionSet', null ],
|
||||
[ 'break-b', 'enter', 'SelectionSet', null ],
|
||||
[ 'break-a', 'enter', 'Field', null ],
|
||||
[ 'break-b', 'enter', 'Field', null ],
|
||||
[ 'break-a', 'enter', 'Name', 'a' ],
|
||||
[ 'break-b', 'enter', 'Name', 'a' ],
|
||||
[ 'break-b', 'leave', 'Name', 'a' ],
|
||||
[ 'break-b', 'enter', 'SelectionSet', null ],
|
||||
[ 'break-b', 'enter', 'Field', null ],
|
||||
[ 'break-b', 'enter', 'Name', 'y' ],
|
||||
[ 'break-b', 'leave', 'Name', 'y' ],
|
||||
[ 'break-b', 'leave', 'Field', null ],
|
||||
[ 'break-b', 'leave', 'SelectionSet', null ],
|
||||
[ 'break-b', 'leave', 'Field', null ],
|
||||
[ 'break-b', 'enter', 'Field', null ],
|
||||
[ 'break-b', 'enter', 'Name', 'b' ]
|
||||
], $visited);
|
||||
}
|
||||
|
||||
/**
|
||||
* @it allows early exit while leaving
|
||||
*/
|
||||
public function testAllowsEarlyExitWhileLeaving2()
|
||||
{
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a, b { x }, c }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([ [
|
||||
'enter' => function($node) use (&$visited) {
|
||||
$visited[] = ['enter', $node->kind, isset($node->value) ? $node->value : null];
|
||||
},
|
||||
'leave' => function($node) use (&$visited) {
|
||||
$value = isset($node->value) ? $node->value : null;
|
||||
$visited[] = ['leave', $node->kind, $value];
|
||||
if ($node->kind === 'Name' && $value === 'x') {
|
||||
return Visitor::stop();
|
||||
}
|
||||
}
|
||||
] ]));
|
||||
|
||||
$this->assertEquals([
|
||||
[ 'enter', 'Document', null ],
|
||||
[ 'enter', 'OperationDefinition', null ],
|
||||
[ 'enter', 'SelectionSet', null ],
|
||||
[ 'enter', 'Field', null ],
|
||||
[ 'enter', 'Name', 'a' ],
|
||||
[ 'leave', 'Name', 'a' ],
|
||||
[ 'leave', 'Field', null ],
|
||||
[ 'enter', 'Field', null ],
|
||||
[ 'enter', 'Name', 'b' ],
|
||||
[ 'leave', 'Name', 'b' ],
|
||||
[ 'enter', 'SelectionSet', null ],
|
||||
[ 'enter', 'Field', null ],
|
||||
[ 'enter', 'Name', 'x' ],
|
||||
[ 'leave', 'Name', 'x' ]
|
||||
], $visited);
|
||||
}
|
||||
|
||||
/**
|
||||
* @it allows early exit from leaving different points
|
||||
*/
|
||||
public function testAllowsEarlyExitFromLeavingDifferentPoints()
|
||||
{
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a { y }, b { x } }');
|
||||
Visitor::visit($ast, Visitor::visitInParallel([
|
||||
[
|
||||
'enter' => function($node) use (&$visited) {
|
||||
$visited[] = ['break-a', 'enter', $node->kind, isset($node->value) ? $node->value : null];
|
||||
},
|
||||
'leave' => function($node) use (&$visited) {
|
||||
$visited[] = ['break-a', 'leave', $node->kind, isset($node->value) ? $node->value : null];
|
||||
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'a') {
|
||||
return Visitor::stop();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'enter' => function($node) use (&$visited) {
|
||||
$visited[] = ['break-b', 'enter', $node->kind, isset($node->value) ? $node->value : null];
|
||||
},
|
||||
'leave' => function($node) use (&$visited) {
|
||||
$visited[] = ['break-b', 'leave', $node->kind, isset($node->value) ? $node->value : null];
|
||||
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'b') {
|
||||
return Visitor::stop();
|
||||
}
|
||||
}
|
||||
],
|
||||
]));
|
||||
|
||||
$this->assertEquals([
|
||||
[ 'break-a', 'enter', 'Document', null ],
|
||||
[ 'break-b', 'enter', 'Document', null ],
|
||||
[ 'break-a', 'enter', 'OperationDefinition', null ],
|
||||
[ 'break-b', 'enter', 'OperationDefinition', null ],
|
||||
[ 'break-a', 'enter', 'SelectionSet', null ],
|
||||
[ 'break-b', 'enter', 'SelectionSet', null ],
|
||||
[ 'break-a', 'enter', 'Field', null ],
|
||||
[ 'break-b', 'enter', 'Field', null ],
|
||||
[ 'break-a', 'enter', 'Name', 'a' ],
|
||||
[ 'break-b', 'enter', 'Name', 'a' ],
|
||||
[ 'break-a', 'leave', 'Name', 'a' ],
|
||||
[ 'break-b', 'leave', 'Name', 'a' ],
|
||||
[ 'break-a', 'enter', 'SelectionSet', null ],
|
||||
[ 'break-b', 'enter', 'SelectionSet', null ],
|
||||
[ 'break-a', 'enter', 'Field', null ],
|
||||
[ 'break-b', 'enter', 'Field', null ],
|
||||
[ 'break-a', 'enter', 'Name', 'y' ],
|
||||
[ 'break-b', 'enter', 'Name', 'y' ],
|
||||
[ 'break-a', 'leave', 'Name', 'y' ],
|
||||
[ 'break-b', 'leave', 'Name', 'y' ],
|
||||
[ 'break-a', 'leave', 'Field', null ],
|
||||
[ 'break-b', 'leave', 'Field', null ],
|
||||
[ 'break-a', 'leave', 'SelectionSet', null ],
|
||||
[ 'break-b', 'leave', 'SelectionSet', null ],
|
||||
[ 'break-a', 'leave', 'Field', null ],
|
||||
[ 'break-b', 'leave', 'Field', null ],
|
||||
[ 'break-b', 'enter', 'Field', null ],
|
||||
[ 'break-b', 'enter', 'Name', 'b' ],
|
||||
[ 'break-b', 'leave', 'Name', 'b' ],
|
||||
[ 'break-b', 'enter', 'SelectionSet', null ],
|
||||
[ 'break-b', 'enter', 'Field', null ],
|
||||
[ 'break-b', 'enter', 'Name', 'x' ],
|
||||
[ 'break-b', 'leave', 'Name', 'x' ],
|
||||
[ 'break-b', 'leave', 'Field', null ],
|
||||
[ 'break-b', 'leave', 'SelectionSet', null ],
|
||||
[ 'break-b', 'leave', 'Field', null ]
|
||||
], $visited);
|
||||
}
|
||||
|
||||
/**
|
||||
* @it allows for editing on enter
|
||||
*/
|
||||
public function testAllowsForEditingOnEnter2()
|
||||
{
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
|
||||
$editedAst = Visitor::visit($ast, Visitor::visitInParallel([
|
||||
[
|
||||
'enter' => function ($node) use (&$visited) {
|
||||
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'b') {
|
||||
return Visitor::removeNode();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'enter' => function ($node) use (&$visited) {
|
||||
$visited[] = ['enter', $node->kind, isset($node->value) ? $node->value : null];
|
||||
},
|
||||
'leave' => function ($node) use (&$visited) {
|
||||
$visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
|
||||
}
|
||||
],
|
||||
]));
|
||||
|
||||
$this->assertEquals(
|
||||
Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]),
|
||||
$ast
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
Parser::parse('{ a, c { a, c } }', ['noLocation' => true]),
|
||||
$editedAst
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
['enter', 'Document', null],
|
||||
['enter', 'OperationDefinition', null],
|
||||
['enter', 'SelectionSet', null],
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'a'],
|
||||
['leave', 'Name', 'a'],
|
||||
['leave', 'Field', null],
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'c'],
|
||||
['leave', 'Name', 'c'],
|
||||
['enter', 'SelectionSet', null],
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'a'],
|
||||
['leave', 'Name', 'a'],
|
||||
['leave', 'Field', null],
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'c'],
|
||||
['leave', 'Name', 'c'],
|
||||
['leave', 'Field', null],
|
||||
['leave', 'SelectionSet', null],
|
||||
['leave', 'Field', null],
|
||||
['leave', 'SelectionSet', null],
|
||||
['leave', 'OperationDefinition', null],
|
||||
['leave', 'Document', null]
|
||||
], $visited);
|
||||
}
|
||||
|
||||
/**
|
||||
* @it allows for editing on leave
|
||||
*/
|
||||
public function testAllowsForEditingOnLeave2()
|
||||
{
|
||||
$visited = [];
|
||||
|
||||
$ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
|
||||
$editedAst = Visitor::visit($ast, Visitor::visitInParallel([
|
||||
[
|
||||
'leave' => function ($node) use (&$visited) {
|
||||
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'b') {
|
||||
return Visitor::removeNode();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'enter' => function ($node) use (&$visited) {
|
||||
$visited[] = ['enter', $node->kind, isset($node->value) ? $node->value : null];
|
||||
},
|
||||
'leave' => function ($node) use (&$visited) {
|
||||
$visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
|
||||
}
|
||||
],
|
||||
]));
|
||||
|
||||
$this->assertEquals(
|
||||
Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]),
|
||||
$ast
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
Parser::parse('{ a, c { a, c } }', ['noLocation' => true]),
|
||||
$editedAst
|
||||
);
|
||||
|
||||
$this->assertEquals([
|
||||
['enter', 'Document', null],
|
||||
['enter', 'OperationDefinition', null],
|
||||
['enter', 'SelectionSet', null],
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'a'],
|
||||
['leave', 'Name', 'a'],
|
||||
['leave', 'Field', null],
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'b'],
|
||||
['leave', 'Name', 'b'],
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'c'],
|
||||
['leave', 'Name', 'c'],
|
||||
['enter', 'SelectionSet', null],
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'a'],
|
||||
['leave', 'Name', 'a'],
|
||||
['leave', 'Field', null],
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'b'],
|
||||
['leave', 'Name', 'b'],
|
||||
['enter', 'Field', null],
|
||||
['enter', 'Name', 'c'],
|
||||
['leave', 'Name', 'c'],
|
||||
['leave', 'Field', null],
|
||||
['leave', 'SelectionSet', null],
|
||||
['leave', 'Field', null],
|
||||
['leave', 'SelectionSet', null],
|
||||
['leave', 'OperationDefinition', null],
|
||||
['leave', 'Document', null]
|
||||
], $visited);
|
||||
}
|
||||
|
||||
// Describe: visitWithTypeInfo
|
||||
|
||||
/**
|
||||
* @it maintains type info during visit
|
||||
*/
|
||||
public function testMaintainsTypeInfoDuringVisit()
|
||||
{
|
||||
$visited = [];
|
||||
|
||||
$typeInfo = new TypeInfo(TestCase::getDefaultSchema());
|
||||
|
||||
$ast = Parser::parse('{ human(id: 4) { name, pets { name }, unknown } }');
|
||||
Visitor::visit($ast, Visitor::visitWithTypeInfo($typeInfo, [
|
||||
'enter' => function ($node) use ($typeInfo, &$visited) {
|
||||
$parentType = $typeInfo->getParentType();
|
||||
$type = $typeInfo->getType();
|
||||
$inputType = $typeInfo->getInputType();
|
||||
$visited[] = [
|
||||
'enter',
|
||||
$node->kind,
|
||||
$node->kind === 'Name' ? $node->value : null,
|
||||
$parentType ? (string)$parentType : null,
|
||||
$type ? (string)$type : null,
|
||||
$inputType ? (string)$inputType : null
|
||||
];
|
||||
},
|
||||
'leave' => function ($node) use ($typeInfo, &$visited) {
|
||||
$parentType = $typeInfo->getParentType();
|
||||
$type = $typeInfo->getType();
|
||||
$inputType = $typeInfo->getInputType();
|
||||
$visited[] = [
|
||||
'leave',
|
||||
$node->kind,
|
||||
$node->kind === 'Name' ? $node->value : null,
|
||||
$parentType ? (string)$parentType : null,
|
||||
$type ? (string)$type : null,
|
||||
$inputType ? (string)$inputType : null
|
||||
];
|
||||
}
|
||||
]));
|
||||
|
||||
$this->assertEquals([
|
||||
['enter', 'Document', null, null, null, null],
|
||||
['enter', 'OperationDefinition', null, null, 'QueryRoot', null],
|
||||
['enter', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],
|
||||
['enter', 'Field', null, 'QueryRoot', 'Human', null],
|
||||
['enter', 'Name', 'human', 'QueryRoot', 'Human', null],
|
||||
['leave', 'Name', 'human', 'QueryRoot', 'Human', null],
|
||||
['enter', 'Argument', null, 'QueryRoot', 'Human', 'ID'],
|
||||
['enter', 'Name', 'id', 'QueryRoot', 'Human', 'ID'],
|
||||
['leave', 'Name', 'id', 'QueryRoot', 'Human', 'ID'],
|
||||
['enter', 'IntValue', null, 'QueryRoot', 'Human', 'ID'],
|
||||
['leave', 'IntValue', null, 'QueryRoot', 'Human', 'ID'],
|
||||
['leave', 'Argument', null, 'QueryRoot', 'Human', 'ID'],
|
||||
['enter', 'SelectionSet', null, 'Human', 'Human', null],
|
||||
['enter', 'Field', null, 'Human', 'String', null],
|
||||
['enter', 'Name', 'name', 'Human', 'String', null],
|
||||
['leave', 'Name', 'name', 'Human', 'String', null],
|
||||
['leave', 'Field', null, 'Human', 'String', null],
|
||||
['enter', 'Field', null, 'Human', '[Pet]', null],
|
||||
['enter', 'Name', 'pets', 'Human', '[Pet]', null],
|
||||
['leave', 'Name', 'pets', 'Human', '[Pet]', null],
|
||||
['enter', 'SelectionSet', null, 'Pet', '[Pet]', null],
|
||||
['enter', 'Field', null, 'Pet', 'String', null],
|
||||
['enter', 'Name', 'name', 'Pet', 'String', null],
|
||||
['leave', 'Name', 'name', 'Pet', 'String', null],
|
||||
['leave', 'Field', null, 'Pet', 'String', null],
|
||||
['leave', 'SelectionSet', null, 'Pet', '[Pet]', null],
|
||||
['leave', 'Field', null, 'Human', '[Pet]', null],
|
||||
['enter', 'Field', null, 'Human', null, null],
|
||||
['enter', 'Name', 'unknown', 'Human', null, null],
|
||||
['leave', 'Name', 'unknown', 'Human', null, null],
|
||||
['leave', 'Field', null, 'Human', null, null],
|
||||
['leave', 'SelectionSet', null, 'Human', 'Human', null],
|
||||
['leave', 'Field', null, 'QueryRoot', 'Human', null],
|
||||
['leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],
|
||||
['leave', 'OperationDefinition', null, null, 'QueryRoot', null],
|
||||
['leave', 'Document', null, null, null, null]
|
||||
], $visited);
|
||||
}
|
||||
|
||||
/**
|
||||
* @it maintains type info during edit
|
||||
*/
|
||||
public function testMaintainsTypeInfoDuringEdit()
|
||||
{
|
||||
$visited = [];
|
||||
$typeInfo = new TypeInfo(TestCase::getDefaultSchema());
|
||||
|
||||
$ast = Parser::parse(
|
||||
'{ human(id: 4) { name, pets }, alien }'
|
||||
);
|
||||
$editedAst = Visitor::visit($ast, Visitor::visitWithTypeInfo($typeInfo, [
|
||||
'enter' => function ($node) use ($typeInfo, &$visited) {
|
||||
$parentType = $typeInfo->getParentType();
|
||||
$type = $typeInfo->getType();
|
||||
$inputType = $typeInfo->getInputType();
|
||||
$visited[] = [
|
||||
'enter',
|
||||
$node->kind,
|
||||
$node->kind === 'Name' ? $node->value : null,
|
||||
$parentType ? (string)$parentType : null,
|
||||
$type ? (string)$type : null,
|
||||
$inputType ? (string)$inputType : null
|
||||
];
|
||||
|
||||
// Make a query valid by adding missing selection sets.
|
||||
if (
|
||||
$node->kind === 'Field' &&
|
||||
!$node->selectionSet &&
|
||||
Type::isCompositeType(Type::getNamedType($type))
|
||||
) {
|
||||
return new Field([
|
||||
'alias' => $node->alias,
|
||||
'name' => $node->name,
|
||||
'arguments' => $node->arguments,
|
||||
'directives' => $node->directives,
|
||||
'selectionSet' => new SelectionSet([
|
||||
'kind' => 'SelectionSet',
|
||||
'selections' => [
|
||||
new Field([
|
||||
'name' => new Name(['value' => '__typename'])
|
||||
])
|
||||
]
|
||||
])
|
||||
]);
|
||||
}
|
||||
},
|
||||
'leave' => function ($node) use ($typeInfo, &$visited) {
|
||||
$parentType = $typeInfo->getParentType();
|
||||
$type = $typeInfo->getType();
|
||||
$inputType = $typeInfo->getInputType();
|
||||
$visited[] = [
|
||||
'leave',
|
||||
$node->kind,
|
||||
$node->kind === 'Name' ? $node->value : null,
|
||||
$parentType ? (string)$parentType : null,
|
||||
$type ? (string)$type : null,
|
||||
$inputType ? (string)$inputType : null
|
||||
];
|
||||
}
|
||||
]));
|
||||
|
||||
$this->assertEquals(Printer::doPrint(Parser::parse(
|
||||
'{ human(id: 4) { name, pets }, alien }'
|
||||
)), Printer::doPrint($ast));
|
||||
|
||||
$this->assertEquals(Printer::doPrint(Parser::parse(
|
||||
'{ human(id: 4) { name, pets { __typename } }, alien { __typename } }'
|
||||
)), Printer::doPrint($editedAst));
|
||||
|
||||
$this->assertEquals([
|
||||
['enter', 'Document', null, null, null, null],
|
||||
['enter', 'OperationDefinition', null, null, 'QueryRoot', null],
|
||||
['enter', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],
|
||||
['enter', 'Field', null, 'QueryRoot', 'Human', null],
|
||||
['enter', 'Name', 'human', 'QueryRoot', 'Human', null],
|
||||
['leave', 'Name', 'human', 'QueryRoot', 'Human', null],
|
||||
['enter', 'Argument', null, 'QueryRoot', 'Human', 'ID'],
|
||||
['enter', 'Name', 'id', 'QueryRoot', 'Human', 'ID'],
|
||||
['leave', 'Name', 'id', 'QueryRoot', 'Human', 'ID'],
|
||||
['enter', 'IntValue', null, 'QueryRoot', 'Human', 'ID'],
|
||||
['leave', 'IntValue', null, 'QueryRoot', 'Human', 'ID'],
|
||||
['leave', 'Argument', null, 'QueryRoot', 'Human', 'ID'],
|
||||
['enter', 'SelectionSet', null, 'Human', 'Human', null],
|
||||
['enter', 'Field', null, 'Human', 'String', null],
|
||||
['enter', 'Name', 'name', 'Human', 'String', null],
|
||||
['leave', 'Name', 'name', 'Human', 'String', null],
|
||||
['leave', 'Field', null, 'Human', 'String', null],
|
||||
['enter', 'Field', null, 'Human', '[Pet]', null],
|
||||
['enter', 'Name', 'pets', 'Human', '[Pet]', null],
|
||||
['leave', 'Name', 'pets', 'Human', '[Pet]', null],
|
||||
['enter', 'SelectionSet', null, 'Pet', '[Pet]', null],
|
||||
['enter', 'Field', null, 'Pet', 'String!', null],
|
||||
['enter', 'Name', '__typename', 'Pet', 'String!', null],
|
||||
['leave', 'Name', '__typename', 'Pet', 'String!', null],
|
||||
['leave', 'Field', null, 'Pet', 'String!', null],
|
||||
['leave', 'SelectionSet', null, 'Pet', '[Pet]', null],
|
||||
['leave', 'Field', null, 'Human', '[Pet]', null],
|
||||
['leave', 'SelectionSet', null, 'Human', 'Human', null],
|
||||
['leave', 'Field', null, 'QueryRoot', 'Human', null],
|
||||
['enter', 'Field', null, 'QueryRoot', 'Alien', null],
|
||||
['enter', 'Name', 'alien', 'QueryRoot', 'Alien', null],
|
||||
['leave', 'Name', 'alien', 'QueryRoot', 'Alien', null],
|
||||
['enter', 'SelectionSet', null, 'Alien', 'Alien', null],
|
||||
['enter', 'Field', null, 'Alien', 'String!', null],
|
||||
['enter', 'Name', '__typename', 'Alien', 'String!', null],
|
||||
['leave', 'Name', '__typename', 'Alien', 'String!', null],
|
||||
['leave', 'Field', null, 'Alien', 'String!', null],
|
||||
['leave', 'SelectionSet', null, 'Alien', 'Alien', null],
|
||||
['leave', 'Field', null, 'QueryRoot', 'Alien', null],
|
||||
['leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],
|
||||
['leave', 'OperationDefinition', null, null, 'QueryRoot', null],
|
||||
['leave', 'Document', null, null, null, null]
|
||||
], $visited);
|
||||
}
|
||||
}
|
||||
|
@ -15,12 +15,10 @@ use GraphQL\Validator\DocumentValidator;
|
||||
|
||||
abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public $humanType;
|
||||
|
||||
/**
|
||||
* @return Schema
|
||||
*/
|
||||
protected function getDefaultSchema()
|
||||
public static function getDefaultSchema()
|
||||
{
|
||||
$FurColor = null;
|
||||
|
||||
@ -124,7 +122,8 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||
]
|
||||
]);
|
||||
|
||||
$Human = $this->humanType = new ObjectType([
|
||||
$Human = null;
|
||||
$Human = new ObjectType([
|
||||
'name' => 'Human',
|
||||
'isTypeOf' => function() {return true;},
|
||||
'interfaces' => [$Being, $Intelligent],
|
||||
@ -134,7 +133,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||
'args' => ['surname' => ['type' => Type::boolean()]]
|
||||
],
|
||||
'pets' => ['type' => Type::listOf($Pet)],
|
||||
'relatives' => ['type' => function() {return Type::listOf($this->humanType); }],
|
||||
'relatives' => ['type' => function() use (&$Human) {return Type::listOf($Human); }],
|
||||
'iq' => ['type' => Type::int()]
|
||||
]
|
||||
]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user