Skip to content

Commit 07ea968

Browse files
authoredApr 22, 2022
Extract check for possible extensions into a separate rule (#1110)
1 parent d4620e1 commit 07ea968

File tree

5 files changed

+601
-156
lines changed

5 files changed

+601
-156
lines changed
 

‎src/Utils/SchemaExtender.php

+6-69
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,7 @@ public static function extend(
9595
} elseif ($def instanceof TypeDefinitionNode) {
9696
$typeDefinitionMap[$def->name->value] = $def;
9797
} elseif ($def instanceof TypeExtensionNode) {
98-
$extendedTypeName = $def->name->value;
99-
$existingType = $schema->getType($extendedTypeName);
100-
if ($existingType === null) {
101-
throw new Error('Cannot extend type "' . $extendedTypeName . '" because it does not exist in the existing schema.', [$def]);
102-
}
103-
104-
static::assertTypeMatchesExtension($existingType, $def);
105-
static::$typeExtensionsMap[$extendedTypeName][] = $def;
98+
static::$typeExtensionsMap[$def->name->value][] = $def;
10699
} elseif ($def instanceof DirectiveDefinitionNode) {
107100
$directiveDefinitions[] = $def;
108101
}
@@ -191,62 +184,6 @@ protected static function extensionASTNodes(NamedType $type): ?array
191184
);
192185
}
193186

194-
/**
195-
* @param Type&NamedType $type
196-
*
197-
* @throws Error
198-
*/
199-
protected static function assertTypeMatchesExtension(NamedType $type, Node $node): void
200-
{
201-
switch (true) {
202-
case $node instanceof ObjectTypeExtensionNode:
203-
if (! ($type instanceof ObjectType)) {
204-
throw new Error(
205-
'Cannot extend non-object type "' . $type->name . '".',
206-
[$node]
207-
);
208-
}
209-
210-
break;
211-
case $node instanceof InterfaceTypeExtensionNode:
212-
if (! ($type instanceof InterfaceType)) {
213-
throw new Error(
214-
'Cannot extend non-interface type "' . $type->name . '".',
215-
[$node]
216-
);
217-
}
218-
219-
break;
220-
case $node instanceof EnumTypeExtensionNode:
221-
if (! ($type instanceof EnumType)) {
222-
throw new Error(
223-
'Cannot extend non-enum type "' . $type->name . '".',
224-
[$node]
225-
);
226-
}
227-
228-
break;
229-
case $node instanceof UnionTypeExtensionNode:
230-
if (! ($type instanceof UnionType)) {
231-
throw new Error(
232-
'Cannot extend non-union type "' . $type->name . '".',
233-
[$node]
234-
);
235-
}
236-
237-
break;
238-
case $node instanceof InputObjectTypeExtensionNode:
239-
if (! ($type instanceof InputObjectType)) {
240-
throw new Error(
241-
'Cannot extend non-input object type "' . $type->name . '".',
242-
[$node]
243-
);
244-
}
245-
246-
break;
247-
}
248-
}
249-
250187
protected static function extendScalarType(ScalarType $type): CustomScalarType
251188
{
252189
/** @var array<int, ScalarTypeExtensionNode> $extensionASTNodes */
@@ -334,7 +271,7 @@ protected static function extendInputFieldMap(InputObjectType $type): array
334271

335272
if (isset(static::$typeExtensionsMap[$type->name])) {
336273
foreach (static::$typeExtensionsMap[$type->name] as $extension) {
337-
assert($extension instanceof InputObjectTypeExtensionNode, 'proven by assertTypeMatchesExtension()');
274+
assert($extension instanceof InputObjectTypeExtensionNode, 'proven by schema validation');
338275

339276
foreach ($extension->fields as $field) {
340277
$fieldName = $field->name->value;
@@ -369,7 +306,7 @@ protected static function extendEnumValueMap(EnumType $type): array
369306

370307
if (isset(static::$typeExtensionsMap[$type->name])) {
371308
foreach (static::$typeExtensionsMap[$type->name] as $extension) {
372-
assert($extension instanceof EnumTypeExtensionNode, 'proven by assertTypeMatchesExtension()');
309+
assert($extension instanceof EnumTypeExtensionNode, 'proven by schema validation');
373310

374311
foreach ($extension->values as $value) {
375312
$newValueMap[$value->name->value] = static::$astBuilder->buildEnumValue($value);
@@ -392,7 +329,7 @@ protected static function extendUnionPossibleTypes(UnionType $type): array
392329

393330
if (isset(static::$typeExtensionsMap[$type->name])) {
394331
foreach (static::$typeExtensionsMap[$type->name] as $extension) {
395-
assert($extension instanceof UnionTypeExtensionNode, 'proven by assertTypeMatchesExtension()');
332+
assert($extension instanceof UnionTypeExtensionNode, 'proven by schema validation');
396333

397334
foreach ($extension->types as $namedType) {
398335
$possibleTypes[] = static::$astBuilder->buildType($namedType);
@@ -420,7 +357,7 @@ protected static function extendImplementedInterfaces(ImplementingType $type): a
420357
foreach (static::$typeExtensionsMap[$type->name] as $extension) {
421358
assert(
422359
$extension instanceof ObjectTypeExtensionNode || $extension instanceof InterfaceTypeExtensionNode,
423-
'proven by assertTypeMatchesExtension()'
360+
'proven by schema validation'
424361
);
425362

426363
foreach ($extension->interfaces as $namedType) {
@@ -517,7 +454,7 @@ protected static function extendFieldMap(Type $type): array
517454
foreach (static::$typeExtensionsMap[$type->name] as $extension) {
518455
assert(
519456
$extension instanceof ObjectTypeExtensionNode || $extension instanceof InterfaceTypeExtensionNode,
520-
'proven by assertTypeMatchesExtension()'
457+
'proven by schema validation'
521458
);
522459

523460
foreach ($extension->fields as $field) {

‎src/Validator/DocumentValidator.php

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use GraphQL\Validator\Rules\NoUnusedVariables;
2727
use GraphQL\Validator\Rules\OverlappingFieldsCanBeMerged;
2828
use GraphQL\Validator\Rules\PossibleFragmentSpreads;
29+
use GraphQL\Validator\Rules\PossibleTypeExtensions;
2930
use GraphQL\Validator\Rules\ProvidedRequiredArguments;
3031
use GraphQL\Validator\Rules\ProvidedRequiredArgumentsOnDirectives;
3132
use GraphQL\Validator\Rules\QueryComplexity;
@@ -210,6 +211,7 @@ public static function sdlRules(): array
210211
KnownDirectives::class => new KnownDirectives(),
211212
KnownArgumentNamesOnDirectives::class => new KnownArgumentNamesOnDirectives(),
212213
UniqueDirectivesPerLocation::class => new UniqueDirectivesPerLocation(),
214+
PossibleTypeExtensions::class => new PossibleTypeExtensions(),
213215
UniqueArgumentNames::class => new UniqueArgumentNames(),
214216
UniqueEnumValueNames::class => new UniqueEnumValueNames(),
215217
UniqueInputFieldNames::class => new UniqueInputFieldNames(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace GraphQL\Validator\Rules;
4+
5+
use GraphQL\Error\Error;
6+
use GraphQL\Error\InvariantViolation;
7+
use GraphQL\Language\AST\Node;
8+
use GraphQL\Language\AST\NodeKind;
9+
use GraphQL\Language\AST\TypeDefinitionNode;
10+
use GraphQL\Language\VisitorOperation;
11+
use GraphQL\Type\Definition\EnumType;
12+
use GraphQL\Type\Definition\InputObjectType;
13+
use GraphQL\Type\Definition\InterfaceType;
14+
use GraphQL\Type\Definition\NamedType;
15+
use GraphQL\Type\Definition\ObjectType;
16+
use GraphQL\Type\Definition\ScalarType;
17+
use GraphQL\Type\Definition\UnionType;
18+
use GraphQL\Utils\Utils;
19+
use GraphQL\Validator\SDLValidationContext;
20+
21+
/**
22+
* Possible type extension.
23+
*
24+
* A type extension is only valid if the type is defined and has the same kind.
25+
*/
26+
class PossibleTypeExtensions extends ValidationRule
27+
{
28+
public function getSDLVisitor(SDLValidationContext $context): array
29+
{
30+
$schema = $context->getSchema();
31+
32+
/** @var array<string, TypeDefinitionNode&Node> $definedTypes */
33+
$definedTypes = [];
34+
foreach ($context->getDocument()->definitions as $def) {
35+
if ($def instanceof TypeDefinitionNode) {
36+
$definedTypes[$def->name->value] = $def;
37+
}
38+
}
39+
40+
$checkTypeExtension = static function ($node) use ($context, $schema, &$definedTypes): ?VisitorOperation {
41+
$typeName = $node->name->value;
42+
$defNode = $definedTypes[$typeName] ?? null;
43+
$existingType = $schema !== null
44+
? $schema->getType($typeName)
45+
: null;
46+
47+
$expectedKind = null;
48+
if ($defNode !== null) {
49+
$expectedKind = self::defKindToExtKind($defNode->kind);
50+
} elseif ($existingType !== null) {
51+
$expectedKind = self::typeToExtKind($existingType);
52+
}
53+
54+
if ($expectedKind !== null) {
55+
if ($expectedKind !== $node->kind) {
56+
$kindStr = self::extensionKindToTypeName($node->kind);
57+
$context->reportError(
58+
new Error(
59+
'Cannot extend non-' . $kindStr . ' type "' . $typeName . '".',
60+
$defNode !== null
61+
? [$defNode, $node]
62+
: $node,
63+
),
64+
);
65+
}
66+
} else {
67+
$existingTypesMap = $schema !== null
68+
? $schema->getTypeMap()
69+
: [];
70+
$allTypeNames = [
71+
...array_keys($definedTypes),
72+
...array_keys($existingTypesMap),
73+
];
74+
$suggestedTypes = Utils::suggestionList($typeName, $allTypeNames);
75+
$didYouMean = \count($suggestedTypes) > 0
76+
? ' Did you mean ' . Utils::quotedOrList($suggestedTypes) . '?'
77+
: '';
78+
$context->reportError(
79+
new Error(
80+
'Cannot extend type "' . $typeName . '" because it is not defined.' . $didYouMean,
81+
$node->name,
82+
),
83+
);
84+
}
85+
86+
return null;
87+
};
88+
89+
return [
90+
NodeKind::SCALAR_TYPE_EXTENSION => $checkTypeExtension,
91+
NodeKind::OBJECT_TYPE_EXTENSION => $checkTypeExtension,
92+
NodeKind::INTERFACE_TYPE_EXTENSION => $checkTypeExtension,
93+
NodeKind::UNION_TYPE_EXTENSION => $checkTypeExtension,
94+
NodeKind::ENUM_TYPE_EXTENSION => $checkTypeExtension,
95+
NodeKind::INPUT_OBJECT_TYPE_EXTENSION => $checkTypeExtension,
96+
];
97+
}
98+
99+
private static function defKindToExtKind(string $kind): string
100+
{
101+
switch ($kind) {
102+
case NodeKind::SCALAR_TYPE_DEFINITION:
103+
return NodeKind::SCALAR_TYPE_EXTENSION;
104+
case NodeKind::OBJECT_TYPE_DEFINITION:
105+
return NodeKind::OBJECT_TYPE_EXTENSION;
106+
case NodeKind::INTERFACE_TYPE_DEFINITION:
107+
return NodeKind::INTERFACE_TYPE_EXTENSION;
108+
case NodeKind::UNION_TYPE_DEFINITION:
109+
return NodeKind::UNION_TYPE_EXTENSION;
110+
case NodeKind::ENUM_TYPE_DEFINITION:
111+
return NodeKind::ENUM_TYPE_EXTENSION;
112+
case NodeKind::INPUT_OBJECT_TYPE_DEFINITION:
113+
return NodeKind::INPUT_OBJECT_TYPE_EXTENSION;
114+
default:
115+
throw new InvariantViolation("Unexpected definition kind: {$kind}");
116+
}
117+
}
118+
119+
private static function typeToExtKind(NamedType $type): string
120+
{
121+
switch (true) {
122+
case $type instanceof ScalarType:
123+
return NodeKind::SCALAR_TYPE_EXTENSION;
124+
case $type instanceof ObjectType:
125+
return NodeKind::OBJECT_TYPE_EXTENSION;
126+
case $type instanceof InterfaceType:
127+
return NodeKind::INTERFACE_TYPE_EXTENSION;
128+
case $type instanceof UnionType:
129+
return NodeKind::UNION_TYPE_EXTENSION;
130+
case $type instanceof EnumType:
131+
return NodeKind::ENUM_TYPE_EXTENSION;
132+
case $type instanceof InputObjectType:
133+
return NodeKind::INPUT_OBJECT_TYPE_EXTENSION;
134+
default:
135+
throw new InvariantViolation('Unexpected type: ' . Utils::printSafe($type));
136+
}
137+
}
138+
139+
private static function extensionKindToTypeName(string $kind): string
140+
{
141+
switch ($kind) {
142+
case NodeKind::SCALAR_TYPE_EXTENSION:
143+
return 'scalar';
144+
case NodeKind::OBJECT_TYPE_EXTENSION:
145+
return 'object';
146+
case NodeKind::INTERFACE_TYPE_EXTENSION:
147+
return 'interface';
148+
case NodeKind::UNION_TYPE_EXTENSION:
149+
return 'union';
150+
case NodeKind::ENUM_TYPE_EXTENSION:
151+
return 'enum';
152+
case NodeKind::INPUT_OBJECT_TYPE_EXTENSION:
153+
return 'input object';
154+
default:
155+
throw new InvariantViolation("Unexpected extension kind: {$kind}");
156+
}
157+
}
158+
}

‎tests/Utils/SchemaExtenderLegacyTest.php

-87
Original file line numberDiff line numberDiff line change
@@ -234,91 +234,4 @@ public function testDoesNotAllowReplacingAnExistingField(): void
234234
self::assertEquals($existingFieldError('SomeInput', 'fooArg'), $error->getMessage());
235235
}
236236
}
237-
238-
// Extract check for possible extensions into a separate rule (#1643)
239-
240-
/**
241-
* @see it('does not allow extending an unknown type')
242-
*/
243-
public function testDoesNotAllowExtendingAnUnknownType(): void
244-
{
245-
$sdls = [
246-
'extend scalar UnknownType @foo',
247-
'extend type UnknownType @foo',
248-
'extend interface UnknownType @foo',
249-
'extend enum UnknownType @foo',
250-
'extend union UnknownType @foo',
251-
'extend input UnknownType @foo',
252-
];
253-
254-
foreach ($sdls as $sdl) {
255-
try {
256-
$this->extendTestSchema($sdl);
257-
self::fail();
258-
} catch (Error $error) {
259-
self::assertEquals('Cannot extend type "UnknownType" because it does not exist in the existing schema.', $error->getMessage());
260-
}
261-
}
262-
}
263-
264-
/**
265-
* @see it('does not allow extending a mismatch type')
266-
*/
267-
public function testDoesNotAllowExtendingAMismatchType(): void
268-
{
269-
$typeSDL = '
270-
extend type SomeInterface @foo
271-
';
272-
273-
try {
274-
$this->extendTestSchema($typeSDL);
275-
self::fail();
276-
} catch (Error $error) {
277-
self::assertEquals('Cannot extend non-object type "SomeInterface".', $error->getMessage());
278-
}
279-
280-
$interfaceSDL = '
281-
extend interface Foo @foo
282-
';
283-
284-
try {
285-
$this->extendTestSchema($interfaceSDL);
286-
self::fail();
287-
} catch (Error $error) {
288-
self::assertEquals('Cannot extend non-interface type "Foo".', $error->getMessage());
289-
}
290-
291-
$enumSDL = '
292-
extend enum Foo @foo
293-
';
294-
295-
try {
296-
$this->extendTestSchema($enumSDL);
297-
self::fail();
298-
} catch (Error $error) {
299-
self::assertEquals('Cannot extend non-enum type "Foo".', $error->getMessage());
300-
}
301-
302-
$unionSDL = '
303-
extend union Foo @foo
304-
';
305-
306-
try {
307-
$this->extendTestSchema($unionSDL);
308-
self::fail();
309-
} catch (Error $error) {
310-
self::assertEquals('Cannot extend non-union type "Foo".', $error->getMessage());
311-
}
312-
313-
$inputSDL = '
314-
extend input Foo @foo
315-
';
316-
317-
try {
318-
$this->extendTestSchema($inputSDL);
319-
self::fail();
320-
} catch (Error $error) {
321-
self::assertEquals('Cannot extend non-input object type "Foo".', $error->getMessage());
322-
}
323-
}
324237
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,435 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace GraphQL\Tests\Validator;
4+
5+
use GraphQL\Type\Schema;
6+
use GraphQL\Utils\BuildSchema;
7+
use GraphQL\Validator\Rules\PossibleTypeExtensions;
8+
9+
final class PossibleTypeExtensionsTest extends ValidatorTestCase
10+
{
11+
/**
12+
* @param array<int, array<string, mixed>> $errors
13+
*/
14+
private function expectSDLErrors(string $sdlString, ?Schema $schema, array $errors): void
15+
{
16+
$this->expectSDLErrorsFromRule(new PossibleTypeExtensions(), $sdlString, $schema, $errors);
17+
}
18+
19+
/**
20+
* @see describe('Validate: Possible type extensions')
21+
* @see it('no extensions')
22+
*/
23+
public function testNoExtensions(): void
24+
{
25+
$this->expectValidSDL(
26+
new PossibleTypeExtensions(),
27+
'
28+
scalar FooScalar
29+
type FooObject
30+
interface FooInterface
31+
union FooUnion
32+
enum FooEnum
33+
input FooInputObject
34+
'
35+
);
36+
}
37+
38+
/**
39+
* @see it('one extension per type')
40+
*/
41+
public function testOneExtensionPerType(): void
42+
{
43+
$this->expectValidSDL(
44+
new PossibleTypeExtensions(),
45+
'
46+
scalar FooScalar
47+
type FooObject
48+
interface FooInterface
49+
union FooUnion
50+
enum FooEnum
51+
input FooInputObject
52+
53+
extend scalar FooScalar @dummy
54+
extend type FooObject @dummy
55+
extend interface FooInterface @dummy
56+
extend union FooUnion @dummy
57+
extend enum FooEnum @dummy
58+
extend input FooInputObject @dummy
59+
'
60+
);
61+
}
62+
63+
/**
64+
* @see it('many extensions per type')
65+
*/
66+
public function testManyExtensionsPerType(): void
67+
{
68+
$this->expectValidSDL(
69+
new PossibleTypeExtensions(),
70+
'
71+
scalar FooScalar
72+
type FooObject
73+
interface FooInterface
74+
union FooUnion
75+
enum FooEnum
76+
input FooInputObject
77+
78+
extend scalar FooScalar @dummy
79+
extend type FooObject @dummy
80+
extend interface FooInterface @dummy
81+
extend union FooUnion @dummy
82+
extend enum FooEnum @dummy
83+
extend input FooInputObject @dummy
84+
85+
extend scalar FooScalar @dummy
86+
extend type FooObject @dummy
87+
extend interface FooInterface @dummy
88+
extend union FooUnion @dummy
89+
extend enum FooEnum @dummy
90+
extend input FooInputObject @dummy
91+
'
92+
);
93+
}
94+
95+
/**
96+
* @see it('extending unknown type')
97+
*/
98+
public function testExtendingUnknownType(): void
99+
{
100+
$message = 'Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?';
101+
$this->expectSDLErrors(
102+
'
103+
type Known
104+
105+
extend scalar Unknown @dummy
106+
extend type Unknown @dummy
107+
extend interface Unknown @dummy
108+
extend union Unknown @dummy
109+
extend enum Unknown @dummy
110+
extend input Unknown @dummy
111+
',
112+
null,
113+
[
114+
[
115+
'message' => $message,
116+
'locations' => [
117+
['line' => 4, 'column' => 21],
118+
],
119+
],
120+
[
121+
'message' => $message,
122+
'locations' => [
123+
['line' => 5, 'column' => 19],
124+
],
125+
],
126+
[
127+
'message' => $message,
128+
'locations' => [
129+
['line' => 6, 'column' => 24],
130+
],
131+
],
132+
[
133+
'message' => $message,
134+
'locations' => [
135+
['line' => 7, 'column' => 20],
136+
],
137+
],
138+
[
139+
'message' => $message,
140+
'locations' => [
141+
['line' => 8, 'column' => 19],
142+
],
143+
],
144+
[
145+
'message' => $message,
146+
'locations' => [
147+
['line' => 9, 'column' => 20],
148+
],
149+
],
150+
],
151+
);
152+
}
153+
154+
/**
155+
* @see it('does not consider non-type definitions')
156+
*/
157+
public function testDoesNotConsiderNonTypeDefinitions(): void
158+
{
159+
$message = 'Cannot extend type "Foo" because it is not defined.';
160+
$this->expectSDLErrors(
161+
'
162+
query Foo { __typename }
163+
fragment Foo on Query { __typename }
164+
directive @Foo on SCHEMA
165+
166+
extend scalar Foo @dummy
167+
extend type Foo @dummy
168+
extend interface Foo @dummy
169+
extend union Foo @dummy
170+
extend enum Foo @dummy
171+
extend input Foo @dummy
172+
',
173+
null,
174+
[
175+
[
176+
'message' => $message,
177+
'locations' => [
178+
['line' => 6, 'column' => 21],
179+
],
180+
],
181+
[
182+
'message' => $message,
183+
'locations' => [
184+
['line' => 7, 'column' => 19],
185+
],
186+
],
187+
[
188+
'message' => $message,
189+
'locations' => [
190+
['line' => 8, 'column' => 24],
191+
],
192+
],
193+
[
194+
'message' => $message,
195+
'locations' => [
196+
['line' => 9, 'column' => 20],
197+
],
198+
],
199+
[
200+
'message' => $message,
201+
'locations' => [
202+
['line' => 10, 'column' => 19],
203+
],
204+
],
205+
[
206+
'message' => $message,
207+
'locations' => [
208+
['line' => 11, 'column' => 20],
209+
],
210+
],
211+
],
212+
);
213+
}
214+
215+
/**
216+
* @see it('extending with different kinds')
217+
*/
218+
public function testExtendingWithDifferentKinds(): void
219+
{
220+
$this->expectSDLErrors(
221+
'
222+
scalar FooScalar
223+
type FooObject
224+
interface FooInterface
225+
union FooUnion
226+
enum FooEnum
227+
input FooInputObject
228+
229+
extend type FooScalar @dummy
230+
extend interface FooObject @dummy
231+
extend union FooInterface @dummy
232+
extend enum FooUnion @dummy
233+
extend input FooEnum @dummy
234+
extend scalar FooInputObject @dummy
235+
',
236+
null,
237+
[
238+
[
239+
'message' => 'Cannot extend non-object type "FooScalar".',
240+
'locations' => [
241+
['line' => 2, 'column' => 7],
242+
['line' => 9, 'column' => 7],
243+
],
244+
],
245+
[
246+
'message' => 'Cannot extend non-interface type "FooObject".',
247+
'locations' => [
248+
['line' => 3, 'column' => 7],
249+
['line' => 10, 'column' => 7],
250+
],
251+
],
252+
[
253+
'message' => 'Cannot extend non-union type "FooInterface".',
254+
'locations' => [
255+
['line' => 4, 'column' => 7],
256+
['line' => 11, 'column' => 7],
257+
],
258+
],
259+
[
260+
'message' => 'Cannot extend non-enum type "FooUnion".',
261+
'locations' => [
262+
['line' => 5, 'column' => 7],
263+
['line' => 12, 'column' => 7],
264+
],
265+
],
266+
[
267+
'message' => 'Cannot extend non-input object type "FooEnum".',
268+
'locations' => [
269+
['line' => 6, 'column' => 7],
270+
['line' => 13, 'column' => 7],
271+
],
272+
],
273+
[
274+
'message' => 'Cannot extend non-scalar type "FooInputObject".',
275+
'locations' => [
276+
['line' => 7, 'column' => 7],
277+
['line' => 14, 'column' => 7],
278+
],
279+
],
280+
],
281+
);
282+
}
283+
284+
/**
285+
* @see it('extending types within existing schema')
286+
*/
287+
public function testExtendingTypesWithinExistingSchema(): void
288+
{
289+
$schema = BuildSchema::build('
290+
scalar FooScalar
291+
type FooObject
292+
interface FooInterface
293+
union FooUnion
294+
enum FooEnum
295+
input FooInputObject
296+
');
297+
$sdl = '
298+
extend scalar FooScalar @dummy
299+
extend type FooObject @dummy
300+
extend interface FooInterface @dummy
301+
extend union FooUnion @dummy
302+
extend enum FooEnum @dummy
303+
extend input FooInputObject @dummy
304+
';
305+
$this->expectValidSDL(
306+
new PossibleTypeExtensions(),
307+
$sdl,
308+
$schema,
309+
);
310+
}
311+
312+
/**
313+
* @see it('extending unknown types within existing schema')
314+
*/
315+
public function testExtendingUnknownTypesWithinExistingSchema(): void
316+
{
317+
$schema = BuildSchema::build('type Known');
318+
$sdl = '
319+
extend scalar Unknown @dummy
320+
extend type Unknown @dummy
321+
extend interface Unknown @dummy
322+
extend union Unknown @dummy
323+
extend enum Unknown @dummy
324+
extend input Unknown @dummy
325+
';
326+
$message = 'Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?';
327+
$this->expectSDLErrors(
328+
$sdl,
329+
$schema,
330+
[
331+
[
332+
'message' => $message,
333+
'locations' => [
334+
['line' => 2, 'column' => 21],
335+
],
336+
],
337+
[
338+
'message' => $message,
339+
'locations' => [
340+
['line' => 3, 'column' => 19],
341+
],
342+
],
343+
[
344+
'message' => $message,
345+
'locations' => [
346+
['line' => 4, 'column' => 24],
347+
],
348+
],
349+
[
350+
'message' => $message,
351+
'locations' => [
352+
['line' => 5, 'column' => 20],
353+
],
354+
],
355+
[
356+
'message' => $message,
357+
'locations' => [
358+
['line' => 6, 'column' => 19],
359+
],
360+
],
361+
[
362+
'message' => $message,
363+
'locations' => [
364+
['line' => 7, 'column' => 20],
365+
],
366+
],
367+
],
368+
);
369+
}
370+
371+
/**
372+
* @see it('extending types with different kinds within existing schema')
373+
*/
374+
public function testExtendingTypesWithDifferentKindsWithinExistingSchema(): void
375+
{
376+
$schema = BuildSchema::build('
377+
scalar FooScalar
378+
type FooObject
379+
interface FooInterface
380+
union FooUnion
381+
enum FooEnum
382+
input FooInputObject
383+
');
384+
$sdl = '
385+
extend type FooScalar @dummy
386+
extend interface FooObject @dummy
387+
extend union FooInterface @dummy
388+
extend enum FooUnion @dummy
389+
extend input FooEnum @dummy
390+
extend scalar FooInputObject @dummy
391+
';
392+
$this->expectSDLErrors(
393+
$sdl,
394+
$schema,
395+
[
396+
[
397+
'message' => 'Cannot extend non-object type "FooScalar".',
398+
'locations' => [
399+
['line' => 2, 'column' => 7],
400+
],
401+
],
402+
[
403+
'message' => 'Cannot extend non-interface type "FooObject".',
404+
'locations' => [
405+
['line' => 3, 'column' => 7],
406+
],
407+
],
408+
[
409+
'message' => 'Cannot extend non-union type "FooInterface".',
410+
'locations' => [
411+
['line' => 4, 'column' => 7],
412+
],
413+
],
414+
[
415+
'message' => 'Cannot extend non-enum type "FooUnion".',
416+
'locations' => [
417+
['line' => 5, 'column' => 7],
418+
],
419+
],
420+
[
421+
'message' => 'Cannot extend non-input object type "FooEnum".',
422+
'locations' => [
423+
['line' => 6, 'column' => 7],
424+
],
425+
],
426+
[
427+
'message' => 'Cannot extend non-scalar type "FooInputObject".',
428+
'locations' => [
429+
['line' => 7, 'column' => 7],
430+
],
431+
],
432+
],
433+
);
434+
}
435+
}

0 commit comments

Comments
 (0)
Please sign in to comment.