Fixed visitor; more visitor tests

This commit is contained in:
vladar 2016-04-30 20:39:06 +06:00
parent 71924f1154
commit e82f887918
3 changed files with 672 additions and 7 deletions

View File

@ -256,7 +256,9 @@ class Visitor
array_pop($path); array_pop($path);
continue; continue;
} }
$editValue = null; if ($result->removeNode) {
$editValue = null;
}
} else { } else {
$editValue = $result; $editValue = $result;
} }
@ -312,7 +314,6 @@ class Visitor
*/ */
static function visitInParallel($visitors) static function visitInParallel($visitors)
{ {
// TODO: implement real parallel visiting once PHP supports it
$visitorsCount = count($visitors); $visitorsCount = count($visitors);
$skipping = new \SplFixedArray($visitorsCount); $skipping = new \SplFixedArray($visitorsCount);
@ -330,6 +331,8 @@ class Visitor
$skipping[$i] = $node; $skipping[$i] = $node;
} else if ($result->doBreak) { } else if ($result->doBreak) {
$skipping[$i] = $result; $skipping[$i] = $result;
} else if ($result->removeNode) {
return $result;
} }
} else if ($result !== null) { } else if ($result !== null) {
return $result; return $result;
@ -348,6 +351,8 @@ class Visitor
if ($result instanceof VisitorOperation) { if ($result instanceof VisitorOperation) {
if ($result->doBreak) { if ($result->doBreak) {
$skipping[$i] = $result; $skipping[$i] = $result;
} else if ($result->removeNode) {
return $result;
} }
} else if ($result !== null) { } else if ($result !== null) {
return $result; return $result;

View File

@ -8,7 +8,11 @@ use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\OperationDefinition; use GraphQL\Language\AST\OperationDefinition;
use GraphQL\Language\AST\SelectionSet; use GraphQL\Language\AST\SelectionSet;
use GraphQL\Language\Parser; use GraphQL\Language\Parser;
use GraphQL\Language\Printer;
use GraphQL\Language\Visitor; use GraphQL\Language\Visitor;
use GraphQL\Tests\Validator\TestCase;
use GraphQL\Type\Definition\Type;
use GraphQL\Utils\TypeInfo;
class VisitorTest extends \PHPUnit_Framework_TestCase class VisitorTest extends \PHPUnit_Framework_TestCase
{ {
@ -643,4 +647,661 @@ class VisitorTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($expected, $visited); $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);
}
} }

View File

@ -15,12 +15,10 @@ use GraphQL\Validator\DocumentValidator;
abstract class TestCase extends \PHPUnit_Framework_TestCase abstract class TestCase extends \PHPUnit_Framework_TestCase
{ {
public $humanType;
/** /**
* @return Schema * @return Schema
*/ */
protected function getDefaultSchema() public static function getDefaultSchema()
{ {
$FurColor = null; $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', 'name' => 'Human',
'isTypeOf' => function() {return true;}, 'isTypeOf' => function() {return true;},
'interfaces' => [$Being, $Intelligent], 'interfaces' => [$Being, $Intelligent],
@ -134,7 +133,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
'args' => ['surname' => ['type' => Type::boolean()]] 'args' => ['surname' => ['type' => Type::boolean()]]
], ],
'pets' => ['type' => Type::listOf($Pet)], '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()] 'iq' => ['type' => Type::int()]
] ]
]); ]);