Passed
Push — master ( 21e0c8...7c1977 )
by Vladimir
06:02
created

testRejectsAnInterfaceNotImplementedByAtLeastOneObject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 16
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Tests\Type;
6
7
use GraphQL\Error\Error;
8
use GraphQL\Error\InvariantViolation;
9
use GraphQL\Error\Warning;
10
use GraphQL\Type\Definition\CustomScalarType;
11
use GraphQL\Type\Definition\EnumType;
12
use GraphQL\Type\Definition\InputObjectType;
13
use GraphQL\Type\Definition\InterfaceType;
14
use GraphQL\Type\Definition\ObjectType;
15
use GraphQL\Type\Definition\ScalarType;
16
use GraphQL\Type\Definition\Type;
17
use GraphQL\Type\Definition\UnionType;
18
use GraphQL\Type\Schema;
19
use GraphQL\Utils\BuildSchema;
20
use GraphQL\Utils\Utils;
21
use PHPUnit\Framework\TestCase;
22
use function array_map;
23
use function array_merge;
24
use function implode;
25
use function print_r;
26
use function sprintf;
27
28
class ValidationTest extends TestCase
29
{
30
    /** @var ScalarType */
31
    public $SomeScalarType;
32
33
    /** @var ObjectType */
34
    public $SomeObjectType;
35
36
    /** @var UnionType */
37
    public $SomeUnionType;
38
39
    /** @var InterfaceType */
40
    public $SomeInterfaceType;
41
42
    /** @var EnumType */
43
    public $SomeEnumType;
44
45
    /** @var InputObjectType */
46
    public $SomeInputObjectType;
47
48
    /** @var mixed[] */
49
    public $outputTypes;
50
51
    /** @var mixed[] */
52
    public $notOutputTypes;
53
54
    /** @var mixed[] */
55
    public $inputTypes;
56
57
    /** @var mixed[] */
58
    public $notInputTypes;
59
60
    /** @var float */
61
    public $Number;
62
63
    public function setUp()
64
    {
65
        $this->Number = 1;
66
67
        $this->SomeScalarType = new CustomScalarType([
68
            'name'         => 'SomeScalar',
69
            'serialize'    => static function () {
70
            },
71
            'parseValue'   => static function () {
72
            },
73
            'parseLiteral' => static function () {
74
            },
75
        ]);
76
77
        $this->SomeInterfaceType = new InterfaceType([
78
            'name'   => 'SomeInterface',
79
            'fields' => ['f' => ['type' => Type::string()]],
80
        ]);
81
82
        $this->SomeObjectType = new ObjectType([
83
            'name'       => 'SomeObject',
84
            'fields'     => ['f' => ['type' => Type::string()]],
85
            'interfaces' => function () {
86
                return [$this->SomeInterfaceType];
87
            },
88
        ]);
89
90
        $this->SomeUnionType = new UnionType([
91
            'name'  => 'SomeUnion',
92
            'types' => [$this->SomeObjectType],
93
        ]);
94
95
        $this->SomeEnumType = new EnumType([
96
            'name'   => 'SomeEnum',
97
            'values' => [
98
                'ONLY' => [],
99
            ],
100
        ]);
101
102
        $this->SomeInputObjectType = new InputObjectType([
103
            'name'   => 'SomeInputObject',
104
            'fields' => [
105
                'val' => ['type' => Type::string(), 'defaultValue' => 'hello'],
106
            ],
107
        ]);
108
109
        $this->outputTypes = $this->withModifiers([
110
            Type::string(),
111
            $this->SomeScalarType,
112
            $this->SomeEnumType,
113
            $this->SomeObjectType,
114
            $this->SomeUnionType,
115
            $this->SomeInterfaceType,
116
        ]);
117
118
        $this->notOutputTypes   = $this->withModifiers([
119
            $this->SomeInputObjectType,
120
        ]);
121
        $this->notOutputTypes[] = $this->Number;
122
123
        $this->inputTypes = $this->withModifiers([
124
            Type::string(),
125
            $this->SomeScalarType,
126
            $this->SomeEnumType,
127
            $this->SomeInputObjectType,
128
        ]);
129
130
        $this->notInputTypes = $this->withModifiers([
131
            $this->SomeObjectType,
132
            $this->SomeUnionType,
133
            $this->SomeInterfaceType,
134
        ]);
135
136
        $this->notInputTypes[] = $this->Number;
137
138
        Warning::suppress(Warning::WARNING_NOT_A_TYPE);
139
    }
140
141
    private function withModifiers($types)
142
    {
143
        return array_merge(
144
            $types,
145
            Utils::map(
146
                $types,
147
                static function ($type) {
148
                    return Type::listOf($type);
149
                }
150
            ),
151
            Utils::map(
152
                $types,
153
                static function ($type) {
154
                    return Type::nonNull($type);
155
                }
156
            ),
157
            Utils::map(
158
                $types,
159
                static function ($type) {
160
                    return Type::nonNull(Type::listOf($type));
161
                }
162
            )
163
        );
164
    }
165
166
    public function tearDown()
167
    {
168
        parent::tearDown();
169
        Warning::enable(Warning::WARNING_NOT_A_TYPE);
170
    }
171
172
    public function testRejectsTypesWithoutNames() : void
173
    {
174
        $this->assertEachCallableThrows(
175
            [
176
                static function () {
177
                    return new ObjectType([]);
178
                },
179
                static function () {
180
                    return new EnumType([]);
181
                },
182
                static function () {
183
                    return new InputObjectType([]);
184
                },
185
                static function () {
186
                    return new UnionType([]);
187
                },
188
                static function () {
189
                    return new InterfaceType([]);
190
                },
191
            ],
192
            'Must provide name.'
193
        );
194
    }
195
196
    /**
197
     * DESCRIBE: Type System: A Schema must have Object root types
198
     */
199
    private function assertEachCallableThrows($closures, $expectedError)
200
    {
201
        foreach ($closures as $index => $factory) {
202
            try {
203
                $factory();
204
                self::fail('Expected exception not thrown for entry ' . $index);
205
            } catch (InvariantViolation $e) {
206
                self::assertEquals($expectedError, $e->getMessage(), 'Error in callable #' . $index);
207
            }
208
        }
209
    }
210
211
    /**
212
     * @see it('accepts a Schema whose query type is an object type')
213
     */
214
    public function testAcceptsASchemaWhoseQueryTypeIsAnObjectType() : void
215
    {
216
        $schema = BuildSchema::build('
217
      type Query {
218
        test: String
219
      }
220
        ');
221
        self::assertEquals([], $schema->validate());
222
223
        $schemaWithDef = BuildSchema::build('
224
      schema {
225
        query: QueryRoot
226
      }
227
      type QueryRoot {
228
        test: String
229
      }
230
    ');
231
        self::assertEquals([], $schemaWithDef->validate());
232
    }
233
234
    /**
235
     * @see it('accepts a Schema whose query and mutation types are object types')
236
     */
237
    public function testAcceptsASchemaWhoseQueryAndMutationTypesAreObjectTypes() : void
238
    {
239
        $schema = BuildSchema::build('
240
      type Query {
241
        test: String
242
      }
243
244
      type Mutation {
245
        test: String
246
      }
247
        ');
248
        self::assertEquals([], $schema->validate());
249
250
        $schema = BuildSchema::build('
251
      schema {
252
        query: QueryRoot
253
        mutation: MutationRoot
254
      }
255
256
      type QueryRoot {
257
        test: String
258
      }
259
260
      type MutationRoot {
261
        test: String
262
      }
263
        ');
264
        self::assertEquals([], $schema->validate());
265
    }
266
267
    /**
268
     * @see it('accepts a Schema whose query and subscription types are object types')
269
     */
270
    public function testAcceptsASchemaWhoseQueryAndSubscriptionTypesAreObjectTypes() : void
271
    {
272
        $schema = BuildSchema::build('
273
      type Query {
274
        test: String
275
      }
276
277
      type Subscription {
278
        test: String
279
      }
280
        ');
281
        self::assertEquals([], $schema->validate());
282
283
        $schema = BuildSchema::build('
284
      schema {
285
        query: QueryRoot
286
        subscription: SubscriptionRoot
287
      }
288
289
      type QueryRoot {
290
        test: String
291
      }
292
293
      type SubscriptionRoot {
294
        test: String
295
      }
296
        ');
297
        self::assertEquals([], $schema->validate());
298
    }
299
300
    /**
301
     * @see it('rejects a Schema without a query type')
302
     */
303
    public function testRejectsASchemaWithoutAQueryType() : void
304
    {
305
        $schema = BuildSchema::build('
306
      type Mutation {
307
        test: String
308
      }
309
        ');
310
311
        $this->assertContainsValidationMessage(
312
            $schema->validate(),
313
            [['message' => 'Query root type must be provided.']]
314
        );
315
316
        $schemaWithDef = BuildSchema::build('
317
      schema {
318
        mutation: MutationRoot
319
      }
320
321
      type MutationRoot {
322
        test: String
323
      }
324
        ');
325
326
        $this->assertContainsValidationMessage(
327
            $schemaWithDef->validate(),
328
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...=> 2, 'column' => 7)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

328
            /** @scrutinizer ignore-type */ [[
Loading history...
329
                'message'   => 'Query root type must be provided.',
330
                'locations' => [['line' => 2, 'column' => 7]],
331
            ],
332
            ]
333
        );
334
    }
335
336
    /**
337
     * @param InvariantViolation[]|Error[] $array
338
     * @param string[][]                   $messages
339
     */
340
    private function assertContainsValidationMessage($array, $messages)
341
    {
342
        $allErrors = implode(
343
            "\n",
344
            array_map(
345
                static function ($error) {
346
                    return $error->getMessage();
347
                },
348
                $array
349
            )
350
        );
351
352
        foreach ($messages as $expected) {
353
            $msg       = $expected['message'];
354
            $locations = $expected['locations'] ?? [];
355
            foreach ($array as $actual) {
356
                if ($actual instanceof Error && $actual->getMessage() === $msg) {
357
                    $actualLocations = [];
358
                    foreach ($actual->getLocations() as $location) {
359
                        $actualLocations[] = $location->toArray();
360
                    }
361
                    self::assertEquals(
362
                        $locations,
363
                        $actualLocations,
364
                        sprintf(
365
                            'Locations do not match for error: %s\n\nExpected:\n%s\n\nActual:\n%s',
366
                            $msg,
367
                            print_r($locations, true),
368
                            print_r($actualLocations, true)
369
                        )
370
                    );
371
                    // Found and valid, so check the next message (and don't fail)
372
                    continue 2;
373
                }
374
            }
375
            self::fail(sprintf("Expected error not found:\n%s\n\nActual errors:\n%s", $msg, $allErrors));
376
        }
377
    }
378
379
    /**
380
     * @see it('rejects a Schema whose query root type is not an Object type')
381
     */
382
    public function testRejectsASchemaWhoseQueryTypeIsNotAnObjectType() : void
383
    {
384
        $schema = BuildSchema::build('
385
      input Query {
386
        test: String
387
      }
388
        ');
389
390
        $this->assertContainsValidationMessage(
391
            $schema->validate(),
392
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...=> 2, 'column' => 7)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

392
            /** @scrutinizer ignore-type */ [[
Loading history...
393
                'message'   => 'Query root type must be Object type, it cannot be Query.',
394
                'locations' => [['line' => 2, 'column' => 7]],
395
            ],
396
            ]
397
        );
398
399
        $schemaWithDef = BuildSchema::build('
400
      schema {
401
        query: SomeInputObject
402
      }
403
404
      input SomeInputObject {
405
        test: String
406
      }
407
        ');
408
409
        $this->assertContainsValidationMessage(
410
            $schemaWithDef->validate(),
411
            [[
412
                'message'   => 'Query root type must be Object type, it cannot be SomeInputObject.',
413
                'locations' => [['line' => 3, 'column' => 16]],
414
            ],
415
            ]
416
        );
417
    }
418
419
    /**
420
     * @see it('rejects a Schema whose mutation type is an input type')
421
     */
422
    public function testRejectsASchemaWhoseMutationTypeIsAnInputType() : void
423
    {
424
        $schema = BuildSchema::build('
425
      type Query {
426
        field: String
427
      }
428
429
      input Mutation {
430
        test: String
431
      }
432
        ');
433
434
        $this->assertContainsValidationMessage(
435
            $schema->validate(),
436
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...=> 6, 'column' => 7)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

436
            /** @scrutinizer ignore-type */ [[
Loading history...
437
                'message'   => 'Mutation root type must be Object type if provided, it cannot be Mutation.',
438
                'locations' => [['line' => 6, 'column' => 7]],
439
            ],
440
            ]
441
        );
442
443
        $schemaWithDef = BuildSchema::build('
444
      schema {
445
        query: Query
446
        mutation: SomeInputObject
447
      }
448
449
      type Query {
450
        field: String
451
      }
452
453
      input SomeInputObject {
454
        test: String
455
      }
456
        ');
457
458
        $this->assertContainsValidationMessage(
459
            $schemaWithDef->validate(),
460
            [[
461
                'message'   => 'Mutation root type must be Object type if provided, it cannot be SomeInputObject.',
462
                'locations' => [['line' => 4, 'column' => 19]],
463
            ],
464
            ]
465
        );
466
    }
467
468
    // DESCRIBE: Type System: Objects must have fields
469
470
    /**
471
     * @see it('rejects a Schema whose subscription type is an input type')
472
     */
473
    public function testRejectsASchemaWhoseSubscriptionTypeIsAnInputType() : void
474
    {
475
        $schema = BuildSchema::build('
476
      type Query {
477
        field: String
478
      }
479
480
      input Subscription {
481
        test: String
482
      }
483
        ');
484
485
        $this->assertContainsValidationMessage(
486
            $schema->validate(),
487
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...=> 6, 'column' => 7)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

487
            /** @scrutinizer ignore-type */ [[
Loading history...
488
                'message'   => 'Subscription root type must be Object type if provided, it cannot be Subscription.',
489
                'locations' => [['line' => 6, 'column' => 7]],
490
            ],
491
            ]
492
        );
493
494
        $schemaWithDef = BuildSchema::build('
495
      schema {
496
        query: Query
497
        subscription: SomeInputObject
498
      }
499
500
      type Query {
501
        field: String
502
      }
503
504
      input SomeInputObject {
505
        test: String
506
      }
507
        ');
508
509
        $this->assertContainsValidationMessage(
510
            $schemaWithDef->validate(),
511
            [[
512
                'message'   => 'Subscription root type must be Object type if provided, it cannot be SomeInputObject.',
513
                'locations' => [['line' => 4, 'column' => 23]],
514
            ],
515
            ]
516
        );
517
    }
518
519
    /**
520
     * @see it('rejects a Schema whose directives are incorrectly typed')
521
     */
522
    public function testRejectsASchemaWhoseDirectivesAreIncorrectlyTyped() : void
523
    {
524
        $schema = new Schema([
525
            'query'      => $this->SomeObjectType,
526
            'directives' => ['somedirective'],
527
        ]);
528
529
        $this->assertContainsValidationMessage(
530
            $schema->validate(),
531
            [['message' => 'Expected directive but got: somedirective.']]
532
        );
533
    }
534
535
    /**
536
     * @see it('accepts an Object type with fields object')
537
     */
538
    public function testAcceptsAnObjectTypeWithFieldsObject() : void
539
    {
540
        $schema = BuildSchema::build('
541
      type Query {
542
        field: SomeObject
543
      }
544
545
      type SomeObject {
546
        field: String
547
      }
548
        ');
549
550
        self::assertEquals([], $schema->validate());
551
    }
552
553
    /**
554
     * @see it('rejects an Object type with missing fields')
555
     */
556
    public function testRejectsAnObjectTypeWithMissingFields() : void
557
    {
558
        $schema = BuildSchema::build('
559
      type Query {
560
        test: IncompleteObject
561
      }
562
563
      type IncompleteObject
564
        ');
565
566
        $this->assertContainsValidationMessage(
567
            $schema->validate(),
568
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...=> 6, 'column' => 7)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

568
            /** @scrutinizer ignore-type */ [[
Loading history...
569
                'message'   => 'Type IncompleteObject must define one or more fields.',
570
                'locations' => [['line' => 6, 'column' => 7]],
571
            ],
572
            ]
573
        );
574
575
        $manualSchema = $this->schemaWithFieldType(
576
            new ObjectType([
577
                'name'   => 'IncompleteObject',
578
                'fields' => [],
579
            ])
580
        );
581
582
        $this->assertContainsValidationMessage(
583
            $manualSchema->validate(),
584
            [['message' => 'Type IncompleteObject must define one or more fields.']]
585
        );
586
587
        $manualSchema2 = $this->schemaWithFieldType(
588
            new ObjectType([
589
                'name'   => 'IncompleteObject',
590
                'fields' => static function () {
591
                    return [];
592
                },
593
            ])
594
        );
595
596
        $this->assertContainsValidationMessage(
597
            $manualSchema2->validate(),
598
            [['message' => 'Type IncompleteObject must define one or more fields.']]
599
        );
600
    }
601
602
    /**
603
     * DESCRIBE: Type System: Fields args must be properly named
604
     */
605
    private function schemaWithFieldType($type) : Schema
606
    {
607
        $ifaceImplementation = new ObjectType([
608
            'name' => 'SomeInterfaceImplementation',
609
            'fields' => ['f' => ['type' => Type::string()]],
610
            'interfaces' => [ $this->SomeInterfaceType ],
611
        ]);
612
613
        return new Schema([
614
            'query' => new ObjectType([
615
                'name'   => 'Query',
616
                'fields' => ['f' => ['type' => $type]],
617
            ]),
618
            'types' => [$type, $ifaceImplementation],
619
        ]);
620
    }
621
622
    /**
623
     * @see it('rejects an Object type with incorrectly named fields')
624
     */
625
    public function testRejectsAnObjectTypeWithIncorrectlyNamedFields() : void
626
    {
627
        $schema = $this->schemaWithFieldType(
628
            new ObjectType([
629
                'name'   => 'SomeObject',
630
                'fields' => [
631
                    'bad-name-with-dashes' => ['type' => Type::string()],
632
                ],
633
            ])
634
        );
635
636
        $this->assertContainsValidationMessage(
637
            $schema->validate(),
638
            [[
639
                'message' => 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but ' .
640
                    '"bad-name-with-dashes" does not.',
641
            ],
642
            ]
643
        );
644
    }
645
646
    /**
647
     * DESCRIBE: Type System: Union types must be valid
648
     */
649
    public function testAcceptsShorthandNotationForFields() : void
650
    {
651
        $this->expectNotToPerformAssertions();
652
        $schema = $this->schemaWithFieldType(
653
            new ObjectType([
654
                'name'   => 'SomeObject',
655
                'fields' => [
656
                    'field' => Type::string(),
657
                ],
658
            ])
659
        );
660
        $schema->assertValid();
661
    }
662
663
    /**
664
     * @see it('accepts field args with valid names')
665
     */
666
    public function testAcceptsFieldArgsWithValidNames() : void
667
    {
668
        $schema = $this->schemaWithFieldType(new ObjectType([
669
            'name'   => 'SomeObject',
670
            'fields' => [
671
                'goodField' => [
672
                    'type' => Type::string(),
673
                    'args' => [
674
                        'goodArg' => ['type' => Type::string()],
675
                    ],
676
                ],
677
            ],
678
        ]));
679
        self::assertEquals([], $schema->validate());
680
    }
681
682
    /**
683
     * @see it('rejects field arg with invalid names')
684
     */
685
    public function testRejectsFieldArgWithInvalidNames() : void
686
    {
687
        $QueryType = new ObjectType([
688
            'name'   => 'SomeObject',
689
            'fields' => [
690
                'badField' => [
691
                    'type' => Type::string(),
692
                    'args' => [
693
                        'bad-name-with-dashes' => ['type' => Type::string()],
694
                    ],
695
                ],
696
            ],
697
        ]);
698
        $schema    = new Schema(['query' => $QueryType]);
699
700
        $this->assertContainsValidationMessage(
701
            $schema->validate(),
702
            [['message' => 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "bad-name-with-dashes" does not.']]
703
        );
704
    }
705
706
    /**
707
     * @see it('accepts a Union type with member types')
708
     */
709
    public function testAcceptsAUnionTypeWithArrayTypes() : void
710
    {
711
        $schema = BuildSchema::build('
712
      type Query {
713
        test: GoodUnion
714
      }
715
716
      type TypeA {
717
        field: String
718
      }
719
720
      type TypeB {
721
        field: String
722
      }
723
724
      union GoodUnion =
725
        | TypeA
726
        | TypeB
727
        ');
728
729
        self::assertEquals([], $schema->validate());
730
    }
731
732
    // DESCRIBE: Type System: Input Objects must have fields
733
734
    /**
735
     * @see it('rejects a Union type with empty types')
736
     */
737
    public function testRejectsAUnionTypeWithEmptyTypes() : void
738
    {
739
        $schema = BuildSchema::build('
740
      type Query {
741
        test: BadUnion
742
      }
743
744
      union BadUnion
745
        ');
746
        $this->assertContainsValidationMessage(
747
            $schema->validate(),
748
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...=> 6, 'column' => 7)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

748
            /** @scrutinizer ignore-type */ [[
Loading history...
749
                'message'   => 'Union type BadUnion must define one or more member types.',
750
                'locations' => [['line' => 6, 'column' => 7]],
751
            ],
752
            ]
753
        );
754
    }
755
756
    /**
757
     * @see it('rejects a Union type with duplicated member type')
758
     */
759
    public function testRejectsAUnionTypeWithDuplicatedMemberType() : void
760
    {
761
        $schema = BuildSchema::build('
762
      type Query {
763
        test: BadUnion
764
      }
765
766
      type TypeA {
767
        field: String
768
      }
769
770
      type TypeB {
771
        field: String
772
      }
773
774
      union BadUnion =
775
        | TypeA
776
        | TypeB
777
        | TypeA
778
        ');
779
        $this->assertContainsValidationMessage(
780
            $schema->validate(),
781
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>... 17, 'column' => 11)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

781
            /** @scrutinizer ignore-type */ [[
Loading history...
782
                'message'   => 'Union type BadUnion can only include type TypeA once.',
783
                'locations' => [['line' => 15, 'column' => 11], ['line' => 17, 'column' => 11]],
784
            ],
785
            ]
786
        );
787
    }
788
789
    /**
790
     * @see it('rejects a Union type with non-Object members types')
791
     */
792
    public function testRejectsAUnionTypeWithNonObjectMembersType() : void
793
    {
794
        $schema = BuildSchema::build('
795
      type Query {
796
        test: BadUnion
797
      }
798
799
      type TypeA {
800
        field: String
801
      }
802
803
      type TypeB {
804
        field: String
805
      }
806
807
      union BadUnion =
808
        | TypeA
809
        | String
810
        | TypeB
811
        ');
812
        $this->assertContainsValidationMessage(
813
            $schema->validate(),
814
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>... 16, 'column' => 11)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

814
            /** @scrutinizer ignore-type */ [[
Loading history...
815
                'message'   => 'Union type BadUnion can only include Object types, ' .
816
                    'it cannot include String.',
817
                'locations' => [['line' => 16, 'column' => 11]],
818
            ],
819
            ]
820
        );
821
822
        $badUnionMemberTypes = [
823
            Type::string(),
824
            Type::nonNull($this->SomeObjectType),
825
            Type::listOf($this->SomeObjectType),
826
            $this->SomeInterfaceType,
827
            $this->SomeUnionType,
828
            $this->SomeEnumType,
829
            $this->SomeInputObjectType,
830
        ];
831
832
        foreach ($badUnionMemberTypes as $memberType) {
833
            $badSchema = $this->schemaWithFieldType(
834
                new UnionType(['name' => 'BadUnion', 'types' => [$memberType]])
835
            );
836
            $this->assertContainsValidationMessage(
837
                $badSchema->validate(),
838
                [[
839
                    'message' => 'Union type BadUnion can only include Object types, ' .
840
                        'it cannot include ' . Utils::printSafe($memberType) . '.',
841
                ],
842
                ]
843
            );
844
        }
845
    }
846
847
    // DESCRIBE: Type System: Enum types must be well defined
848
849
    /**
850
     * @see it('accepts an Input Object type with fields')
851
     */
852
    public function testAcceptsAnInputObjectTypeWithFields() : void
853
    {
854
        $schema = BuildSchema::build('
855
      type Query {
856
        field(arg: SomeInputObject): String
857
      }
858
859
      input SomeInputObject {
860
        field: String
861
      }
862
        ');
863
        self::assertEquals([], $schema->validate());
864
    }
865
866
    /**
867
     * @see it('rejects an Input Object type with missing fields')
868
     */
869
    public function testRejectsAnInputObjectTypeWithMissingFields() : void
870
    {
871
        $schema = BuildSchema::build('
872
      type Query {
873
        field(arg: SomeInputObject): String
874
      }
875
876
      input SomeInputObject
877
        ');
878
        $this->assertContainsValidationMessage(
879
            $schema->validate(),
880
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...=> 6, 'column' => 7)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

880
            /** @scrutinizer ignore-type */ [[
Loading history...
881
                'message'   => 'Input Object type SomeInputObject must define one or more fields.',
882
                'locations' => [['line' => 6, 'column' => 7]],
883
            ],
884
            ]
885
        );
886
    }
887
888
    /**
889
     * @see it('rejects an Input Object type with incorrectly typed fields')
890
     */
891
    public function testRejectsAnInputObjectTypeWithIncorrectlyTypedFields() : void
892
    {
893
        $schema = BuildSchema::build('
894
      type Query {
895
        field(arg: SomeInputObject): String
896
      }
897
      
898
      type SomeObject {
899
        field: String
900
      }
901
902
      union SomeUnion = SomeObject
903
      
904
      input SomeInputObject {
905
        badObject: SomeObject
906
        badUnion: SomeUnion
907
        goodInputObject: SomeInputObject
908
      }
909
        ');
910
        $this->assertContainsValidationMessage(
911
            $schema->validate(),
912
            [
0 ignored issues
show
Bug introduced by
array(array('message' =>... 14, 'column' => 19)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

912
            /** @scrutinizer ignore-type */ [
Loading history...
913
                [
914
                    'message'   => 'The type of SomeInputObject.badObject must be Input Type but got: SomeObject.',
915
                    'locations' => [['line' => 13, 'column' => 20]],
916
                ],
917
                [
918
                    'message'   => 'The type of SomeInputObject.badUnion must be Input Type but got: SomeUnion.',
919
                    'locations' => [['line' => 14, 'column' => 19]],
920
                ],
921
            ]
922
        );
923
    }
924
925
    /**
926
     * @see it('rejects an Enum type without values')
927
     */
928
    public function testRejectsAnEnumTypeWithoutValues() : void
929
    {
930
        $schema = BuildSchema::build('
931
      type Query {
932
        field: SomeEnum
933
      }
934
      
935
      enum SomeEnum
936
        ');
937
        $this->assertContainsValidationMessage(
938
            $schema->validate(),
939
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...=> 6, 'column' => 7)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

939
            /** @scrutinizer ignore-type */ [[
Loading history...
940
                'message'   => 'Enum type SomeEnum must define one or more values.',
941
                'locations' => [['line' => 6, 'column' => 7]],
942
            ],
943
            ]
944
        );
945
    }
946
947
    /**
948
     * @see it('rejects an Enum type with duplicate values')
949
     */
950
    public function testRejectsAnEnumTypeWithDuplicateValues() : void
951
    {
952
        $schema = BuildSchema::build('
953
      type Query {
954
        field: SomeEnum
955
      }
956
      
957
      enum SomeEnum {
958
        SOME_VALUE
959
        SOME_VALUE
960
      }
961
        ');
962
        $this->assertContainsValidationMessage(
963
            $schema->validate(),
964
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...=> 8, 'column' => 9)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

964
            /** @scrutinizer ignore-type */ [[
Loading history...
965
                'message'   => 'Enum type SomeEnum can include value SOME_VALUE only once.',
966
                'locations' => [['line' => 7, 'column' => 9], ['line' => 8, 'column' => 9]],
967
            ],
968
            ]
969
        );
970
    }
971
972
    public function testDoesNotAllowIsDeprecatedWithoutDeprecationReasonOnEnum() : void
973
    {
974
        $enum = new EnumType([
975
            'name'   => 'SomeEnum',
976
            'values' => [
977
                'value' => ['isDeprecated' => true],
978
            ],
979
        ]);
980
        $this->expectException(InvariantViolation::class);
981
        $this->expectExceptionMessage('SomeEnum.value should provide "deprecationReason" instead of "isDeprecated".');
982
        $enum->assertValid();
983
    }
984
985
    /**
986
     * DESCRIBE: Type System: Object fields must have output types
987
     *
988
     * @return string[][]
989
     */
990
    public function invalidEnumValueName() : array
991
    {
992
        return [
993
            ['#value', 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "#value" does not.'],
994
            ['1value', 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "1value" does not.'],
995
            ['KEBAB-CASE', 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "KEBAB-CASE" does not.'],
996
            ['false', 'Enum type SomeEnum cannot include value: false.'],
997
            ['true', 'Enum type SomeEnum cannot include value: true.'],
998
            ['null', 'Enum type SomeEnum cannot include value: null.'],
999
        ];
1000
    }
1001
1002
    /**
1003
     * @see          it('rejects an Enum type with incorrectly named values')
1004
     *
1005
     * @dataProvider invalidEnumValueName
1006
     */
1007
    public function testRejectsAnEnumTypeWithIncorrectlyNamedValues($name, $expectedMessage) : void
1008
    {
1009
        $schema = $this->schemaWithEnum($name);
1010
1011
        $this->assertContainsValidationMessage(
1012
            $schema->validate(),
1013
            [['message' => $expectedMessage],
1014
            ]
1015
        );
1016
    }
1017
1018
    private function schemaWithEnum($name)
1019
    {
1020
        return $this->schemaWithFieldType(
1021
            new EnumType([
1022
                'name'   => 'SomeEnum',
1023
                'values' => [
1024
                    $name => [],
1025
                ],
1026
            ])
1027
        );
1028
    }
1029
1030
    /**
1031
     * @see it('accepts an output type as an Object field type')
1032
     */
1033
    public function testAcceptsAnOutputTypeAsNnObjectFieldType() : void
1034
    {
1035
        foreach ($this->outputTypes as $type) {
1036
            $schema = $this->schemaWithObjectFieldOfType($type);
1037
            self::assertEquals([], $schema->validate());
1038
        }
1039
    }
1040
1041
    /**
1042
     * DESCRIBE: Type System: Objects can only implement unique interfaces
1043
     */
1044
    private function schemaWithObjectFieldOfType($fieldType) : Schema
1045
    {
1046
        $BadObjectType = new ObjectType([
1047
            'name'   => 'BadObject',
1048
            'fields' => [
1049
                'badField' => ['type' => $fieldType],
1050
            ],
1051
        ]);
1052
1053
        return new Schema([
1054
            'query' => new ObjectType([
1055
                'name'   => 'Query',
1056
                'fields' => [
1057
                    'f' => ['type' => $BadObjectType],
1058
                ],
1059
            ]),
1060
            'types' => [$this->SomeObjectType],
1061
        ]);
1062
    }
1063
1064
    /**
1065
     * @see it('rejects an empty Object field type')
1066
     */
1067
    public function testRejectsAnEmptyObjectFieldType() : void
1068
    {
1069
        $schema = $this->schemaWithObjectFieldOfType(null);
1070
1071
        $this->assertContainsValidationMessage(
1072
            $schema->validate(),
1073
            [['message' => 'The type of BadObject.badField must be Output Type but got: null.'],
1074
            ]
1075
        );
1076
    }
1077
1078
    /**
1079
     * @see it('rejects a non-output type as an Object field type')
1080
     */
1081
    public function testRejectsANonOutputTypeAsAnObjectFieldType() : void
1082
    {
1083
        foreach ($this->notOutputTypes as $type) {
1084
            $schema = $this->schemaWithObjectFieldOfType($type);
1085
1086
            $this->assertContainsValidationMessage(
1087
                $schema->validate(),
1088
                [[
1089
                    'message' => 'The type of BadObject.badField must be Output Type but got: ' . Utils::printSafe($type) . '.',
1090
                ],
1091
                ]
1092
            );
1093
        }
1094
    }
1095
1096
    /**
1097
     * @see it('rejects with relevant locations for a non-output type as an Object field type')
1098
     */
1099
    public function testRejectsWithReleventLocationsForANonOutputTypeAsAnObjectFieldType() : void
1100
    {
1101
        $schema = BuildSchema::build('
1102
      type Query {
1103
        field: [SomeInputObject]
1104
      }
1105
      
1106
      input SomeInputObject {
1107
        field: String
1108
      }
1109
        ');
1110
        $this->assertContainsValidationMessage(
1111
            $schema->validate(),
1112
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...> 3, 'column' => 16)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1112
            /** @scrutinizer ignore-type */ [[
Loading history...
1113
                'message'   => 'The type of Query.field must be Output Type but got: [SomeInputObject].',
1114
                'locations' => [['line' => 3, 'column' => 16]],
1115
            ],
1116
            ]
1117
        );
1118
    }
1119
1120
    // DESCRIBE: Type System: Interface fields must have output types
1121
1122
    /**
1123
     * @see it('rejects an Object implementing a non-type values')
1124
     */
1125
    public function testRejectsAnObjectImplementingANonTypeValues() : void
1126
    {
1127
        $schema   = new Schema([
1128
            'query' => new ObjectType([
1129
                'name'       => 'BadObject',
1130
                'interfaces' => [null],
1131
                'fields'     => ['a' => Type::string()],
1132
            ]),
1133
        ]);
1134
        $expected = ['message' => 'Type BadObject must only implement Interface types, it cannot implement null.'];
1135
1136
        $this->assertContainsValidationMessage(
1137
            $schema->validate(),
1138
            [$expected]
1139
        );
1140
    }
1141
1142
    /**
1143
     * @see it('rejects an Object implementing a non-Interface type')
1144
     */
1145
    public function testRejectsAnObjectImplementingANonInterfaceType() : void
1146
    {
1147
        $schema = BuildSchema::build('
1148
      type Query {
1149
        field: BadObject
1150
      }
1151
      
1152
      input SomeInputObject {
1153
        field: String
1154
      }
1155
      
1156
      type BadObject implements SomeInputObject {
1157
        field: String
1158
      }
1159
        ');
1160
        $this->assertContainsValidationMessage(
1161
            $schema->validate(),
1162
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>... 10, 'column' => 33)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1162
            /** @scrutinizer ignore-type */ [[
Loading history...
1163
                'message'   => 'Type BadObject must only implement Interface types, it cannot implement SomeInputObject.',
1164
                'locations' => [['line' => 10, 'column' => 33]],
1165
            ],
1166
            ]
1167
        );
1168
    }
1169
1170
    /**
1171
     * @see it('rejects an Object implementing the same interface twice')
1172
     */
1173
    public function testRejectsAnObjectImplementingTheSameInterfaceTwice() : void
1174
    {
1175
        $schema = BuildSchema::build('
1176
      type Query {
1177
        field: AnotherObject
1178
      }
1179
      
1180
      interface AnotherInterface {
1181
        field: String
1182
      }
1183
      
1184
      type AnotherObject implements AnotherInterface & AnotherInterface {
1185
        field: String
1186
      }
1187
        ');
1188
        $this->assertContainsValidationMessage(
1189
            $schema->validate(),
1190
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>... 10, 'column' => 56)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1190
            /** @scrutinizer ignore-type */ [[
Loading history...
1191
                'message'   => 'Type AnotherObject can only implement AnotherInterface once.',
1192
                'locations' => [['line' => 10, 'column' => 37], ['line' => 10, 'column' => 56]],
1193
            ],
1194
            ]
1195
        );
1196
    }
1197
1198
    /**
1199
     * @see it('rejects an Object implementing the same interface twice due to extension')
1200
     */
1201
    public function testRejectsAnObjectImplementingTheSameInterfaceTwiceDueToExtension() : void
1202
    {
1203
        $this->expectNotToPerformAssertions();
1204
        self::markTestIncomplete('extend does not work this way (yet).');
1205
        $schema = BuildSchema::build('
1206
      type Query {
1207
        field: AnotherObject
1208
      }
1209
      
1210
      interface AnotherInterface {
1211
        field: String
1212
      }
1213
      
1214
      type AnotherObject implements AnotherInterface {
1215
        field: String
1216
      }
1217
      
1218
      extend type AnotherObject implements AnotherInterface
1219
        ');
1220
        $this->assertContainsValidationMessage(
1221
            $schema->validate(),
1222
            [[
1223
                'message'   => 'Type AnotherObject can only implement AnotherInterface once.',
1224
                'locations' => [['line' => 10, 'column' => 37], ['line' => 14, 'column' => 38]],
1225
            ],
1226
            ]
1227
        );
1228
    }
1229
1230
    // DESCRIBE: Type System: Field arguments must have input types
1231
1232
    /**
1233
     * @see it('accepts an output type as an Interface field type')
1234
     */
1235
    public function testAcceptsAnOutputTypeAsAnInterfaceFieldType() : void
1236
    {
1237
        foreach ($this->outputTypes as $type) {
1238
            $schema = $this->schemaWithInterfaceFieldOfType($type);
1239
            self::assertEquals([], $schema->validate());
1240
        }
1241
    }
1242
1243
    private function schemaWithInterfaceFieldOfType($fieldType)
1244
    {
1245
        $BadInterfaceType = new InterfaceType([
1246
            'name'   => 'BadInterface',
1247
            'fields' => [
1248
                'badField' => ['type' => $fieldType],
1249
            ],
1250
        ]);
1251
1252
        $BadImplementingType = new ObjectType([
1253
            'name' => 'BadImplementing',
1254
            'interfaces' => [ $BadInterfaceType ],
1255
            'fields' => [
1256
                'badField' => [ 'type' => $fieldType ],
1257
            ],
1258
        ]);
1259
1260
        return new Schema([
1261
            'query' => new ObjectType([
1262
                'name'   => 'Query',
1263
                'fields' => [
1264
                    'f' => ['type' => $BadInterfaceType],
1265
                ],
1266
            ]),
1267
            'types' => [ $BadImplementingType, $this->SomeObjectType ],
1268
        ]);
1269
    }
1270
1271
    /**
1272
     * @see it('rejects an empty Interface field type')
1273
     */
1274
    public function testRejectsAnEmptyInterfaceFieldType() : void
1275
    {
1276
        $schema = $this->schemaWithInterfaceFieldOfType(null);
1277
        $this->assertContainsValidationMessage(
1278
            $schema->validate(),
1279
            [['message' => 'The type of BadInterface.badField must be Output Type but got: null.'],
1280
            ]
1281
        );
1282
    }
1283
1284
    /**
1285
     * @see it('rejects a non-output type as an Interface field type')
1286
     */
1287
    public function testRejectsANonOutputTypeAsAnInterfaceFieldType() : void
1288
    {
1289
        foreach ($this->notOutputTypes as $type) {
1290
            $schema = $this->schemaWithInterfaceFieldOfType($type);
1291
1292
            $this->assertContainsValidationMessage(
1293
                $schema->validate(),
1294
                [[
1295
                    'message' => 'The type of BadInterface.badField must be Output Type but got: ' . Utils::printSafe($type) . '.',
1296
                ],
1297
                ]
1298
            );
1299
        }
1300
    }
1301
1302
    // DESCRIBE: Type System: Input Object fields must have input types
1303
1304
    /**
1305
     * @see it('rejects a non-output type as an Interface field type with locations')
1306
     */
1307
    public function testRejectsANonOutputTypeAsAnInterfaceFieldTypeWithLocations() : void
1308
    {
1309
        $schema = BuildSchema::build('
1310
      type Query {
1311
        field: SomeInterface
1312
      }
1313
      
1314
      interface SomeInterface {
1315
        field: SomeInputObject
1316
      }
1317
      
1318
      input SomeInputObject {
1319
        foo: String
1320
      }
1321
        ');
1322
        $this->assertContainsValidationMessage(
1323
            $schema->validate(),
1324
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...> 7, 'column' => 16)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1324
            /** @scrutinizer ignore-type */ [[
Loading history...
1325
                'message'   => 'The type of SomeInterface.field must be Output Type but got: SomeInputObject.',
1326
                'locations' => [['line' => 7, 'column' => 16]],
1327
            ],
1328
            ]
1329
        );
1330
    }
1331
1332
    /**
1333
     * @see it('rejects an interface not implemented by at least one object')
1334
     */
1335
    public function testRejectsAnInterfaceNotImplementedByAtLeastOneObject()
1336
    {
1337
        $schema = BuildSchema::build('
1338
      type Query {
1339
        test: SomeInterface
1340
      }
1341
1342
      interface SomeInterface {
1343
        foo: String
1344
      }
1345
        ');
1346
        $this->assertContainsValidationMessage(
1347
            $schema->validate(),
1348
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...=> 6, 'column' => 7)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1348
            /** @scrutinizer ignore-type */ [[
Loading history...
1349
                'message' => 'Interface SomeInterface must be implemented by at least one Object type.',
1350
                'locations' => [[ 'line' => 6, 'column' => 7 ]],
1351
            ],
1352
            ]
1353
        );
1354
    }
1355
1356
    /**
1357
     * @see it('accepts an input type as a field arg type')
1358
     */
1359
    public function testAcceptsAnInputTypeAsAFieldArgType() : void
1360
    {
1361
        foreach ($this->inputTypes as $type) {
1362
            $schema = $this->schemaWithArgOfType($type);
1363
            self::assertEquals([], $schema->validate());
1364
        }
1365
    }
1366
1367
    private function schemaWithArgOfType($argType)
1368
    {
1369
        $BadObjectType = new ObjectType([
1370
            'name'   => 'BadObject',
1371
            'fields' => [
1372
                'badField' => [
1373
                    'type' => Type::string(),
1374
                    'args' => [
1375
                        'badArg' => ['type' => $argType],
1376
                    ],
1377
                ],
1378
            ],
1379
        ]);
1380
1381
        return new Schema([
1382
            'query' => new ObjectType([
1383
                'name'   => 'Query',
1384
                'fields' => [
1385
                    'f' => ['type' => $BadObjectType],
1386
                ],
1387
            ]),
1388
        ]);
1389
    }
1390
1391
    /**
1392
     * @see it('rejects an empty field arg type')
1393
     */
1394
    public function testRejectsAnEmptyFieldArgType() : void
1395
    {
1396
        $schema = $this->schemaWithArgOfType(null);
1397
        $this->assertContainsValidationMessage(
1398
            $schema->validate(),
1399
            [['message' => 'The type of BadObject.badField(badArg:) must be Input Type but got: null.'],
1400
            ]
1401
        );
1402
    }
1403
1404
    // DESCRIBE: Objects must adhere to Interface they implement
1405
1406
    /**
1407
     * @see it('rejects a non-input type as a field arg type')
1408
     */
1409
    public function testRejectsANonInputTypeAsAFieldArgType() : void
1410
    {
1411
        foreach ($this->notInputTypes as $type) {
1412
            $schema = $this->schemaWithArgOfType($type);
1413
            $this->assertContainsValidationMessage(
1414
                $schema->validate(),
1415
                [[
1416
                    'message' => 'The type of BadObject.badField(badArg:) must be Input Type but got: ' . Utils::printSafe($type) . '.',
1417
                ],
1418
                ]
1419
            );
1420
        }
1421
    }
1422
1423
    /**
1424
     * @see it('rejects a non-input type as a field arg with locations')
1425
     */
1426
    public function testANonInputTypeAsAFieldArgWithLocations() : void
1427
    {
1428
        $schema = BuildSchema::build('
1429
      type Query {
1430
        test(arg: SomeObject): String
1431
      }
1432
      
1433
      type SomeObject {
1434
        foo: String
1435
      }
1436
        ');
1437
        $this->assertContainsValidationMessage(
1438
            $schema->validate(),
1439
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...> 3, 'column' => 19)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1439
            /** @scrutinizer ignore-type */ [[
Loading history...
1440
                'message'   => 'The type of Query.test(arg:) must be Input Type but got: SomeObject.',
1441
                'locations' => [['line' => 3, 'column' => 19]],
1442
            ],
1443
            ]
1444
        );
1445
    }
1446
1447
    /**
1448
     * @see it('accepts an input type as an input field type')
1449
     */
1450
    public function testAcceptsAnInputTypeAsAnInputFieldType() : void
1451
    {
1452
        foreach ($this->inputTypes as $type) {
1453
            $schema = $this->schemaWithInputFieldOfType($type);
1454
            self::assertEquals([], $schema->validate());
1455
        }
1456
    }
1457
1458
    private function schemaWithInputFieldOfType($inputFieldType)
1459
    {
1460
        $BadInputObjectType = new InputObjectType([
1461
            'name'   => 'BadInputObject',
1462
            'fields' => [
1463
                'badField' => ['type' => $inputFieldType],
1464
            ],
1465
        ]);
1466
1467
        return new Schema([
1468
            'query' => new ObjectType([
1469
                'name'   => 'Query',
1470
                'fields' => [
1471
                    'f' => [
1472
                        'type' => Type::string(),
1473
                        'args' => [
1474
                            'badArg' => ['type' => $BadInputObjectType],
1475
                        ],
1476
                    ],
1477
                ],
1478
            ]),
1479
        ]);
1480
    }
1481
1482
    /**
1483
     * @see it('rejects an empty input field type')
1484
     */
1485
    public function testRejectsAnEmptyInputFieldType() : void
1486
    {
1487
        $schema = $this->schemaWithInputFieldOfType(null);
1488
        $this->assertContainsValidationMessage(
1489
            $schema->validate(),
1490
            [['message' => 'The type of BadInputObject.badField must be Input Type but got: null.'],
1491
            ]
1492
        );
1493
    }
1494
1495
    /**
1496
     * @see it('rejects a non-input type as an input field type')
1497
     */
1498
    public function testRejectsANonInputTypeAsAnInputFieldType() : void
1499
    {
1500
        foreach ($this->notInputTypes as $type) {
1501
            $schema = $this->schemaWithInputFieldOfType($type);
1502
            $this->assertContainsValidationMessage(
1503
                $schema->validate(),
1504
                [[
1505
                    'message' => 'The type of BadInputObject.badField must be Input Type but got: ' . Utils::printSafe($type) . '.',
1506
                ],
1507
                ]
1508
            );
1509
        }
1510
    }
1511
1512
    /**
1513
     * @see it('rejects a non-input type as an input object field with locations')
1514
     */
1515
    public function testRejectsANonInputTypeAsAnInputObjectFieldWithLocations() : void
1516
    {
1517
        $schema = BuildSchema::build('
1518
      type Query {
1519
        test(arg: SomeInputObject): String
1520
      }
1521
      
1522
      input SomeInputObject {
1523
        foo: SomeObject
1524
      }
1525
      
1526
      type SomeObject {
1527
        bar: String
1528
      }
1529
        ');
1530
        $this->assertContainsValidationMessage(
1531
            $schema->validate(),
1532
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...> 7, 'column' => 14)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1532
            /** @scrutinizer ignore-type */ [[
Loading history...
1533
                'message'   => 'The type of SomeInputObject.foo must be Input Type but got: SomeObject.',
1534
                'locations' => [['line' => 7, 'column' => 14]],
1535
            ],
1536
            ]
1537
        );
1538
    }
1539
1540
    /**
1541
     * @see it('accepts an Object which implements an Interface')
1542
     */
1543
    public function testAcceptsAnObjectWhichImplementsAnInterface() : void
1544
    {
1545
        $schema = BuildSchema::build('
1546
      type Query {
1547
        test: AnotherObject
1548
      }
1549
      
1550
      interface AnotherInterface {
1551
        field(input: String): String
1552
      }
1553
      
1554
      type AnotherObject implements AnotherInterface {
1555
        field(input: String): String
1556
      }
1557
        ');
1558
1559
        self::assertEquals(
1560
            [],
1561
            $schema->validate()
1562
        );
1563
    }
1564
1565
    /**
1566
     * @see it('accepts an Object which implements an Interface along with more fields')
1567
     */
1568
    public function testAcceptsAnObjectWhichImplementsAnInterfaceAlongWithMoreFields() : void
1569
    {
1570
        $schema = BuildSchema::build('
1571
      type Query {
1572
        test: AnotherObject
1573
      }
1574
1575
      interface AnotherInterface {
1576
        field(input: String): String
1577
      }
1578
1579
      type AnotherObject implements AnotherInterface {
1580
        field(input: String): String
1581
        anotherField: String
1582
      }
1583
        ');
1584
1585
        self::assertEquals(
1586
            [],
1587
            $schema->validate()
1588
        );
1589
    }
1590
1591
    /**
1592
     * @see it('accepts an Object which implements an Interface field along with additional optional arguments')
1593
     */
1594
    public function testAcceptsAnObjectWhichImplementsAnInterfaceFieldAlongWithAdditionalOptionalArguments() : void
1595
    {
1596
        $schema = BuildSchema::build('
1597
      type Query {
1598
        test: AnotherObject
1599
      }
1600
1601
      interface AnotherInterface {
1602
        field(input: String): String
1603
      }
1604
1605
      type AnotherObject implements AnotherInterface {
1606
        field(input: String, anotherInput: String): String
1607
      }
1608
        ');
1609
1610
        self::assertEquals(
1611
            [],
1612
            $schema->validate()
1613
        );
1614
    }
1615
1616
    /**
1617
     * @see it('rejects an Object missing an Interface field')
1618
     */
1619
    public function testRejectsAnObjectMissingAnInterfaceField() : void
1620
    {
1621
        $schema = BuildSchema::build('
1622
      type Query {
1623
        test: AnotherObject
1624
      }
1625
1626
      interface AnotherInterface {
1627
        field(input: String): String
1628
      }
1629
1630
      type AnotherObject implements AnotherInterface {
1631
        anotherField: String
1632
      }
1633
        ');
1634
1635
        $this->assertContainsValidationMessage(
1636
            $schema->validate(),
1637
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...> 10, 'column' => 7)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1637
            /** @scrutinizer ignore-type */ [[
Loading history...
1638
                'message'   => 'Interface field AnotherInterface.field expected but ' .
1639
                    'AnotherObject does not provide it.',
1640
                'locations' => [['line' => 7, 'column' => 9], ['line' => 10, 'column' => 7]],
1641
            ],
1642
            ]
1643
        );
1644
    }
1645
1646
    /**
1647
     * @see it('rejects an Object with an incorrectly typed Interface field')
1648
     */
1649
    public function testRejectsAnObjectWithAnIncorrectlyTypedInterfaceField() : void
1650
    {
1651
        $schema = BuildSchema::build('
1652
      type Query {
1653
        test: AnotherObject
1654
      }
1655
1656
      interface AnotherInterface {
1657
        field(input: String): String
1658
      }
1659
1660
      type AnotherObject implements AnotherInterface {
1661
        field(input: String): Int
1662
      }
1663
        ');
1664
1665
        $this->assertContainsValidationMessage(
1666
            $schema->validate(),
1667
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>... 11, 'column' => 31)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1667
            /** @scrutinizer ignore-type */ [[
Loading history...
1668
                'message'   => 'Interface field AnotherInterface.field expects type String but ' .
1669
                    'AnotherObject.field is type Int.',
1670
                'locations' => [['line' => 7, 'column' => 31], ['line' => 11, 'column' => 31]],
1671
            ],
1672
            ]
1673
        );
1674
    }
1675
1676
    /**
1677
     * @see it('rejects an Object with a differently typed Interface field')
1678
     */
1679
    public function testRejectsAnObjectWithADifferentlyTypedInterfaceField() : void
1680
    {
1681
        $schema = BuildSchema::build('
1682
      type Query {
1683
        test: AnotherObject
1684
      }
1685
1686
      type A { foo: String }
1687
      type B { foo: String }
1688
1689
      interface AnotherInterface {
1690
        field: A
1691
      }
1692
1693
      type AnotherObject implements AnotherInterface {
1694
        field: B
1695
      }
1696
        ');
1697
1698
        $this->assertContainsValidationMessage(
1699
            $schema->validate(),
1700
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>... 14, 'column' => 16)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1700
            /** @scrutinizer ignore-type */ [[
Loading history...
1701
                'message'   => 'Interface field AnotherInterface.field expects type A but ' .
1702
                    'AnotherObject.field is type B.',
1703
                'locations' => [['line' => 10, 'column' => 16], ['line' => 14, 'column' => 16]],
1704
            ],
1705
            ]
1706
        );
1707
    }
1708
1709
    /**
1710
     * @see it('accepts an Object with a subtyped Interface field (interface)')
1711
     */
1712
    public function testAcceptsAnObjectWithASubtypedInterfaceFieldForInterface() : void
1713
    {
1714
        $schema = BuildSchema::build('
1715
      type Query {
1716
        test: AnotherObject
1717
      }
1718
1719
      interface AnotherInterface {
1720
        field: AnotherInterface
1721
      }
1722
1723
      type AnotherObject implements AnotherInterface {
1724
        field: AnotherObject
1725
      }
1726
        ');
1727
1728
        self::assertEquals([], $schema->validate());
1729
    }
1730
1731
    /**
1732
     * @see it('accepts an Object with a subtyped Interface field (union)')
1733
     */
1734
    public function testAcceptsAnObjectWithASubtypedInterfaceFieldForUnion() : void
1735
    {
1736
        $schema = BuildSchema::build('
1737
      type Query {
1738
        test: AnotherObject
1739
      }
1740
1741
      type SomeObject {
1742
        field: String
1743
      }
1744
1745
      union SomeUnionType = SomeObject
1746
1747
      interface AnotherInterface {
1748
        field: SomeUnionType
1749
      }
1750
1751
      type AnotherObject implements AnotherInterface {
1752
        field: SomeObject
1753
      }
1754
        ');
1755
1756
        self::assertEquals([], $schema->validate());
1757
    }
1758
1759
    /**
1760
     * @see it('rejects an Object missing an Interface argument')
1761
     */
1762
    public function testRejectsAnObjectMissingAnInterfaceArgument() : void
1763
    {
1764
        $schema = BuildSchema::build('
1765
      type Query {
1766
        test: AnotherObject
1767
      }
1768
1769
      interface AnotherInterface {
1770
        field(input: String): String
1771
      }
1772
1773
      type AnotherObject implements AnotherInterface {
1774
        field: String
1775
      }
1776
        ');
1777
1778
        $this->assertContainsValidationMessage(
1779
            $schema->validate(),
1780
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...> 11, 'column' => 9)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1780
            /** @scrutinizer ignore-type */ [[
Loading history...
1781
                'message'   => 'Interface field argument AnotherInterface.field(input:) expected ' .
1782
                    'but AnotherObject.field does not provide it.',
1783
                'locations' => [['line' => 7, 'column' => 15], ['line' => 11, 'column' => 9]],
1784
            ],
1785
            ]
1786
        );
1787
    }
1788
1789
    /**
1790
     * @see it('rejects an Object with an incorrectly typed Interface argument')
1791
     */
1792
    public function testRejectsAnObjectWithAnIncorrectlyTypedInterfaceArgument() : void
1793
    {
1794
        $schema = BuildSchema::build('
1795
      type Query {
1796
        test: AnotherObject
1797
      }
1798
1799
      interface AnotherInterface {
1800
        field(input: String): String
1801
      }
1802
1803
      type AnotherObject implements AnotherInterface {
1804
        field(input: Int): String
1805
      }
1806
        ');
1807
1808
        $this->assertContainsValidationMessage(
1809
            $schema->validate(),
1810
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>... 11, 'column' => 22)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1810
            /** @scrutinizer ignore-type */ [[
Loading history...
1811
                'message'   => 'Interface field argument AnotherInterface.field(input:) expects ' .
1812
                    'type String but AnotherObject.field(input:) is type Int.',
1813
                'locations' => [['line' => 7, 'column' => 22], ['line' => 11, 'column' => 22]],
1814
            ],
1815
            ]
1816
        );
1817
    }
1818
1819
    /**
1820
     * @see it('rejects an Object with both an incorrectly typed field and argument')
1821
     */
1822
    public function testRejectsAnObjectWithBothAnIncorrectlyTypedFieldAndArgument() : void
1823
    {
1824
        $schema = BuildSchema::build('
1825
      type Query {
1826
        test: AnotherObject
1827
      }
1828
1829
      interface AnotherInterface {
1830
        field(input: String): String
1831
      }
1832
1833
      type AnotherObject implements AnotherInterface {
1834
        field(input: Int): Int
1835
      }
1836
        ');
1837
1838
        $this->assertContainsValidationMessage(
1839
            $schema->validate(),
1840
            [
0 ignored issues
show
Bug introduced by
array(array('message' =>... 11, 'column' => 22)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1840
            /** @scrutinizer ignore-type */ [
Loading history...
1841
                [
1842
                    'message'   => 'Interface field AnotherInterface.field expects type String but ' .
1843
                        'AnotherObject.field is type Int.',
1844
                    'locations' => [['line' => 7, 'column' => 31], ['line' => 11, 'column' => 28]],
1845
                ],
1846
                [
1847
                    'message'   => 'Interface field argument AnotherInterface.field(input:) expects ' .
1848
                        'type String but AnotherObject.field(input:) is type Int.',
1849
                    'locations' => [['line' => 7, 'column' => 22], ['line' => 11, 'column' => 22]],
1850
                ],
1851
            ]
1852
        );
1853
    }
1854
1855
    /**
1856
     * @see it('rejects an Object which implements an Interface field along with additional required arguments')
1857
     */
1858
    public function testRejectsAnObjectWhichImplementsAnInterfaceFieldAlongWithAdditionalRequiredArguments() : void
1859
    {
1860
        $schema = BuildSchema::build('
1861
      type Query {
1862
        test: AnotherObject
1863
      }
1864
1865
      interface AnotherInterface {
1866
        field(input: String): String
1867
      }
1868
1869
      type AnotherObject implements AnotherInterface {
1870
        field(input: String, anotherInput: String!): String
1871
      }
1872
        ');
1873
1874
        $this->assertContainsValidationMessage(
1875
            $schema->validate(),
1876
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>...=> 7, 'column' => 9)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1876
            /** @scrutinizer ignore-type */ [[
Loading history...
1877
                'message'   => 'Object field argument AnotherObject.field(anotherInput:) is of ' .
1878
                    'required type String! but is not also provided by the Interface ' .
1879
                    'field AnotherInterface.field.',
1880
                'locations' => [['line' => 11, 'column' => 44], ['line' => 7, 'column' => 9]],
1881
            ],
1882
            ]
1883
        );
1884
    }
1885
1886
    /**
1887
     * @see it('accepts an Object with an equivalently wrapped Interface field type')
1888
     */
1889
    public function testAcceptsAnObjectWithAnEquivalentlyWrappedInterfaceFieldType() : void
1890
    {
1891
        $schema = BuildSchema::build('
1892
      type Query {
1893
        test: AnotherObject
1894
      }
1895
1896
      interface AnotherInterface {
1897
        field: [String]!
1898
      }
1899
1900
      type AnotherObject implements AnotherInterface {
1901
        field: [String]!
1902
      }
1903
        ');
1904
1905
        self::assertEquals([], $schema->validate());
1906
    }
1907
1908
    /**
1909
     * @see it('rejects an Object with a non-list Interface field list type')
1910
     */
1911
    public function testRejectsAnObjectWithANonListInterfaceFieldListType() : void
1912
    {
1913
        $schema = BuildSchema::build('
1914
      type Query {
1915
        test: AnotherObject
1916
      }
1917
1918
      interface AnotherInterface {
1919
        field: [String]
1920
      }
1921
1922
      type AnotherObject implements AnotherInterface {
1923
        field: String
1924
      }
1925
        ');
1926
1927
        $this->assertContainsValidationMessage(
1928
            $schema->validate(),
1929
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>... 11, 'column' => 16)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1929
            /** @scrutinizer ignore-type */ [[
Loading history...
1930
                'message'   => 'Interface field AnotherInterface.field expects type [String] ' .
1931
                    'but AnotherObject.field is type String.',
1932
                'locations' => [['line' => 7, 'column' => 16], ['line' => 11, 'column' => 16]],
1933
            ],
1934
            ]
1935
        );
1936
    }
1937
1938
    /**
1939
     * @see it('rejects an Object with a list Interface field non-list type')
1940
     */
1941
    public function testRejectsAnObjectWithAListInterfaceFieldNonListType() : void
1942
    {
1943
        $schema = BuildSchema::build('
1944
      type Query {
1945
        test: AnotherObject
1946
      }
1947
1948
      interface AnotherInterface {
1949
        field: String
1950
      }
1951
1952
      type AnotherObject implements AnotherInterface {
1953
        field: [String]
1954
      }
1955
        ');
1956
1957
        $this->assertContainsValidationMessage(
1958
            $schema->validate(),
1959
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>... 11, 'column' => 16)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1959
            /** @scrutinizer ignore-type */ [[
Loading history...
1960
                'message'   => 'Interface field AnotherInterface.field expects type String but ' .
1961
                    'AnotherObject.field is type [String].',
1962
                'locations' => [['line' => 7, 'column' => 16], ['line' => 11, 'column' => 16]],
1963
            ],
1964
            ]
1965
        );
1966
    }
1967
1968
    /**
1969
     * @see it('accepts an Object with a subset non-null Interface field type')
1970
     */
1971
    public function testAcceptsAnObjectWithASubsetNonNullInterfaceFieldType() : void
1972
    {
1973
        $schema = BuildSchema::build('
1974
      type Query {
1975
        test: AnotherObject
1976
      }
1977
1978
      interface AnotherInterface {
1979
        field: String
1980
      }
1981
1982
      type AnotherObject implements AnotherInterface {
1983
        field: String!
1984
      }
1985
        ');
1986
1987
        self::assertEquals([], $schema->validate());
1988
    }
1989
1990
    /**
1991
     * @see it('rejects an Object with a superset nullable Interface field type')
1992
     */
1993
    public function testRejectsAnObjectWithASupersetNullableInterfaceFieldType() : void
1994
    {
1995
        $schema = BuildSchema::build('
1996
      type Query {
1997
        test: AnotherObject
1998
      }
1999
2000
      interface AnotherInterface {
2001
        field: String!
2002
      }
2003
2004
      type AnotherObject implements AnotherInterface {
2005
        field: String
2006
      }
2007
        ');
2008
2009
        $this->assertContainsValidationMessage(
2010
            $schema->validate(),
2011
            [[
0 ignored issues
show
Bug introduced by
array(array('message' =>... 11, 'column' => 16)))) of type array<integer,array<stri...ring,integer>>|string>> is incompatible with the type array<mixed,string[]> expected by parameter $messages of GraphQL\Tests\Type\Valid...ainsValidationMessage(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2011
            /** @scrutinizer ignore-type */ [[
Loading history...
2012
                'message'   => 'Interface field AnotherInterface.field expects type String! ' .
2013
                    'but AnotherObject.field is type String.',
2014
                'locations' => [['line' => 7, 'column' => 16], ['line' => 11, 'column' => 16]],
2015
            ],
2016
            ]
2017
        );
2018
    }
2019
2020
    public function testRejectsDifferentInstancesOfTheSameType() : void
2021
    {
2022
        // Invalid: always creates new instance vs returning one from registry
2023
        $typeLoader = static function ($name) {
2024
            switch ($name) {
2025
                case 'Query':
2026
                    return new ObjectType([
2027
                        'name'   => 'Query',
2028
                        'fields' => [
2029
                            'test' => Type::string(),
2030
                        ],
2031
                    ]);
2032
                default:
2033
                    return null;
2034
            }
2035
        };
2036
2037
        $schema = new Schema([
2038
            'query'      => $typeLoader('Query'),
2039
            'typeLoader' => $typeLoader,
2040
        ]);
2041
        $this->expectException(InvariantViolation::class);
2042
        $this->expectExceptionMessage(
2043
            'Type loader returns different instance for Query than field/argument definitions. ' .
2044
            'Make sure you always return the same instance for the same type name.'
2045
        );
2046
        $schema->assertValid();
2047
    }
2048
}
2049