Failed Conditions
Push — master ( 6e7cf2...804daa )
by Vladimir
04:26
created

SchemaPrinterTest   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 1138
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 32
eloc 684
dl 0
loc 1138
rs 9.756
c 0
b 0
f 0

31 Methods

Rating   Name   Duplication   Size   Complexity  
A printSingleFieldSchema() 0 9 1
A printForTest() 0 5 1
A testPrintMultipleInterface() 0 49 1
A testPrintsStringFieldWithStringArgWithDefault() 0 11 1
A testPrintsStringFieldWithNonNullIntArg() 0 11 1
A testPrintsStringFieldWithMultipleArgs() 0 14 1
A testPrintsStringFieldWithMultipleArgsLastIsDefault() 0 15 1
A testPrintsStringFieldWithMultipleArgsSecondIsDefault() 0 15 1
B testPrintIntrospectionSchemaWithCommentDescriptions() 0 210 1
A testPrintNonNullArrayNonNullStringField() 0 10 1
A testInputType() 0 28 1
A testDoesNotOneLinePrintADescriptionThatEndsWithAQuote() 0 20 1
A testEnum() 0 31 1
A testPrintsStringFieldWithIntArgWithDefault() 0 11 1
A testPrintObjectField() 0 23 1
A testPrintInterface() 0 36 1
A testPrintNonNullArrayStringField() 0 10 1
A testOneLinePrintsAShortDescription() 0 18 1
A testPrintsStringField() 0 10 1
A testPrintNonNullStringField() 0 10 1
A testPrintUnions() 0 50 1
A testCustomScalar() 0 25 2
B testPrintIntrospectionSchema() 0 240 1
A testPrintsStringFieldWithIntArgWithDefaultNull() 0 11 1
A testPrintArrayStringField() 0 10 1
A testPrintsCustomQueryRootType() 0 21 1
A testPrintsStringFieldWithIntArg() 0 11 1
A testPrintsStringFieldWithMultipleArgsFirstIsDefault() 0 15 1
A testPReservesLeadingSpacesWhenPrintingADescription() 0 19 1
A testPrintArrayNonNullStringField() 0 10 1
A testPrintsCustomDirectives() 0 29 1
1
<?php
2
namespace GraphQL\Tests\Utils;
3
4
use GraphQL\Language\DirectiveLocation;
5
use GraphQL\Type\Schema;
6
use GraphQL\Type\Definition\CustomScalarType;
7
use GraphQL\Type\Definition\Directive;
8
use GraphQL\Type\Definition\InputObjectType;
9
use GraphQL\Type\Definition\InterfaceType;
10
use GraphQL\Type\Definition\ObjectType;
11
use GraphQL\Type\Definition\Type;
12
use GraphQL\Type\Definition\EnumType;
13
use GraphQL\Type\Definition\UnionType;
14
use GraphQL\Utils\BuildSchema;
15
use GraphQL\Utils\SchemaPrinter;
16
use PHPUnit\Framework\TestCase;
17
18
class SchemaPrinterTest extends TestCase
19
{
20
    // Describe: Type System Printer
21
22
    private function printForTest($schema)
23
    {
24
        $schemaText = SchemaPrinter::doPrint($schema);
25
        $this->assertEquals($schemaText, SchemaPrinter::doPrint(BuildSchema::build($schemaText)));
26
        return "\n" . $schemaText;
27
    }
28
29
    private function printSingleFieldSchema($fieldConfig)
30
    {
31
        $query = new ObjectType([
32
            'name' => 'Query',
33
            'fields' => [
34
                'singleField' => $fieldConfig
35
            ]
36
        ]);
37
        return $this->printForTest(new Schema(['query' => $query]));
38
    }
39
40
    /**
41
     * @it Prints String Field
42
     */
43
    public function testPrintsStringField()
44
    {
45
        $output = $this->printSingleFieldSchema([
46
            'type' => Type::string()
47
        ]);
48
        $this->assertEquals('
49
type Query {
50
  singleField: String
51
}
52
', $output);
53
    }
54
55
    /**
56
     * @it Prints [String] Field
57
     */
58
    public function testPrintArrayStringField()
59
    {
60
        $output = $this->printSingleFieldSchema([
61
            'type' => Type::listOf(Type::string())
62
        ]);
63
        $this->assertEquals('
64
type Query {
65
  singleField: [String]
66
}
67
', $output);
68
    }
69
70
    /**
71
     * @it Prints String! Field
72
     */
73
    public function testPrintNonNullStringField()
74
    {
75
        $output = $this->printSingleFieldSchema([
76
            'type' => Type::nonNull(Type::string())
77
        ]);
78
        $this->assertEquals('
79
type Query {
80
  singleField: String!
81
}
82
', $output);
83
    }
84
85
    /**
86
     * @it Prints [String]! Field
87
     */
88
    public function testPrintNonNullArrayStringField()
89
    {
90
        $output = $this->printSingleFieldSchema([
91
            'type' => Type::nonNull(Type::listOf(Type::string()))
92
        ]);
93
        $this->assertEquals('
94
type Query {
95
  singleField: [String]!
96
}
97
', $output);
98
    }
99
100
    /**
101
     * @it Prints [String!] Field
102
     */
103
    public function testPrintArrayNonNullStringField()
104
    {
105
        $output = $this->printSingleFieldSchema([
106
            'type' => Type::listOf(Type::nonNull(Type::string()))
107
        ]);
108
        $this->assertEquals('
109
type Query {
110
  singleField: [String!]
111
}
112
', $output);
113
    }
114
115
    /**
116
     * @it Prints [String!]! Field
117
     */
118
    public function testPrintNonNullArrayNonNullStringField()
119
    {
120
        $output = $this->printSingleFieldSchema([
121
            'type' => Type::nonNull(Type::listOf(Type::nonNull(Type::string())))
122
        ]);
123
        $this->assertEquals('
124
type Query {
125
  singleField: [String!]!
126
}
127
', $output);
128
    }
129
130
    /**
131
     * @it Print Object Field
132
     */
133
    public function testPrintObjectField()
134
    {
135
        $fooType = new ObjectType([
136
            'name' => 'Foo',
137
            'fields' => ['str' => ['type' => Type::string()]]
138
        ]);
139
140
        $root = new ObjectType([
141
            'name' => 'Query',
142
            'fields' => ['foo' => ['type' => $fooType]]
143
        ]);
144
145
        $schema = new Schema(['query' => $root]);
146
        $output = $this->printForTest($schema);
147
        $this->assertEquals('
148
type Foo {
149
  str: String
150
}
151
152
type Query {
153
  foo: Foo
154
}
155
', $output);
156
    }
157
158
    /**
159
     * @it Prints String Field With Int Arg
160
     */
161
    public function testPrintsStringFieldWithIntArg()
162
    {
163
        $output = $this->printSingleFieldSchema([
164
            'type' => Type::string(),
165
            'args' => ['argOne' => ['type' => Type::int()]]
166
        ]);
167
        $this->assertEquals('
168
type Query {
169
  singleField(argOne: Int): String
170
}
171
', $output);
172
    }
173
174
    /**
175
     * @it Prints String Field With Int Arg With Default
176
     */
177
    public function testPrintsStringFieldWithIntArgWithDefault()
178
    {
179
        $output = $this->printSingleFieldSchema([
180
            'type' => Type::string(),
181
            'args' => ['argOne' => ['type' => Type::int(), 'defaultValue' => 2]]
182
        ]);
183
        $this->assertEquals('
184
type Query {
185
  singleField(argOne: Int = 2): String
186
}
187
', $output);
188
    }
189
190
    /**
191
     * @it Prints String Field With String Arg With Default
192
     */
193
    public function testPrintsStringFieldWithStringArgWithDefault()
194
    {
195
        $output = $this->printSingleFieldSchema([
196
            'type' => Type::string(),
197
            'args' => ['argOne' => ['type' => Type::string(), 'defaultValue' => "tes\t de\fault"]],
198
        ]);
199
        $this->assertEquals('
200
type Query {
201
  singleField(argOne: String = "tes\t de\fault"): String
202
}
203
', $output);
204
    }
205
206
    /**
207
     * @it Prints String Field With Int Arg With Default Null
208
     */
209
    public function testPrintsStringFieldWithIntArgWithDefaultNull()
210
    {
211
        $output = $this->printSingleFieldSchema([
212
            'type' => Type::string(),
213
            'args' => ['argOne' => ['type' => Type::int(), 'defaultValue' => null]]
214
        ]);
215
        $this->assertEquals('
216
type Query {
217
  singleField(argOne: Int = null): String
218
}
219
', $output);
220
    }
221
222
    /**
223
     * @it Prints String Field With Int! Arg
224
     */
225
    public function testPrintsStringFieldWithNonNullIntArg()
226
    {
227
        $output = $this->printSingleFieldSchema([
228
            'type' => Type::string(),
229
            'args' => ['argOne' => ['type' => Type::nonNull(Type::int())]]
230
        ]);
231
        $this->assertEquals('
232
type Query {
233
  singleField(argOne: Int!): String
234
}
235
', $output);
236
    }
237
238
    /**
239
     * @it Prints String Field With Multiple Args
240
     */
241
    public function testPrintsStringFieldWithMultipleArgs()
242
    {
243
        $output = $this->printSingleFieldSchema([
244
            'type' => Type::string(),
245
            'args' => [
246
                'argOne' => ['type' => Type::int()],
247
                'argTwo' => ['type' => Type::string()]
248
            ]
249
        ]);
250
        $this->assertEquals('
251
type Query {
252
  singleField(argOne: Int, argTwo: String): String
253
}
254
', $output);
255
    }
256
257
    /**
258
     * @it Prints String Field With Multiple Args, First is Default
259
     */
260
    public function testPrintsStringFieldWithMultipleArgsFirstIsDefault()
261
    {
262
        $output = $this->printSingleFieldSchema([
263
            'type' => Type::string(),
264
            'args' => [
265
                'argOne' => ['type' => Type::int(), 'defaultValue' => 1],
266
                'argTwo' => ['type' => Type::string()],
267
                'argThree' => ['type' => Type::boolean()]
268
            ]
269
        ]);
270
        $this->assertEquals('
271
type Query {
272
  singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String
273
}
274
', $output);
275
    }
276
277
    /**
278
     * @it Prints String Field With Multiple Args, Second is Default
279
     */
280
    public function testPrintsStringFieldWithMultipleArgsSecondIsDefault()
281
    {
282
        $output = $this->printSingleFieldSchema([
283
            'type' => Type::string(),
284
            'args' => [
285
                'argOne' => ['type' => Type::int()],
286
                'argTwo' => ['type' => Type::string(), 'defaultValue' => 'foo'],
287
                'argThree' => ['type' => Type::boolean()]
288
            ]
289
        ]);
290
        $this->assertEquals('
291
type Query {
292
  singleField(argOne: Int, argTwo: String = "foo", argThree: Boolean): String
293
}
294
', $output);
295
    }
296
297
    /**
298
     * @it Prints String Field With Multiple Args, Last is Default
299
     */
300
    public function testPrintsStringFieldWithMultipleArgsLastIsDefault()
301
    {
302
        $output = $this->printSingleFieldSchema([
303
            'type' => Type::string(),
304
            'args' => [
305
                'argOne' => ['type' => Type::int()],
306
                'argTwo' => ['type' => Type::string()],
307
                'argThree' => ['type' => Type::boolean(), 'defaultValue' => false]
308
            ]
309
        ]);
310
        $this->assertEquals('
311
type Query {
312
  singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String
313
}
314
', $output);
315
    }
316
317
    /**
318
     * @it Prints custom query root type
319
     */
320
    public function testPrintsCustomQueryRootType()
321
    {
322
        $customQueryType = new ObjectType([
323
            'name' => 'CustomQueryType',
324
            'fields' => ['bar' => ['type' => Type::string()]],
325
        ]);
326
327
        $schema = new Schema([
328
            'query' => $customQueryType,
329
        ]);
330
        $output = $this->printForTest($schema);
331
        $expected = '
332
schema {
333
  query: CustomQueryType
334
}
335
336
type CustomQueryType {
337
  bar: String
338
}
339
';
340
        $this->assertEquals($expected, $output);
341
    }
342
343
    /**
344
     * @it Print Interface
345
     */
346
    public function testPrintInterface()
347
    {
348
        $fooType = new InterfaceType([
349
            'name' => 'Foo',
350
            'fields' => ['str' => ['type' => Type::string()]]
351
        ]);
352
353
        $barType = new ObjectType([
354
            'name' => 'Bar',
355
            'fields' => ['str' => ['type' => Type::string()]],
356
            'interfaces' => [$fooType]
357
        ]);
358
359
        $query = new ObjectType([
360
            'name' => 'Query',
361
            'fields' => ['bar' => ['type' => $barType]]
362
        ]);
363
364
        $schema = new Schema([
365
            'query' => $query,
366
            'types' => [$barType]
367
        ]);
368
        $output = $this->printForTest($schema);
369
        $this->assertEquals('
370
type Bar implements Foo {
371
  str: String
372
}
373
374
interface Foo {
375
  str: String
376
}
377
378
type Query {
379
  bar: Bar
380
}
381
', $output);
382
    }
383
384
    /**
385
     * @it Print Multiple Interface
386
     */
387
    public function testPrintMultipleInterface()
388
    {
389
        $fooType = new InterfaceType([
390
            'name' => 'Foo',
391
            'fields' => ['str' => ['type' => Type::string()]]
392
        ]);
393
394
        $baazType = new InterfaceType([
395
            'name' => 'Baaz',
396
            'fields' => ['int' => ['type' => Type::int()]]
397
        ]);
398
399
        $barType = new ObjectType([
400
            'name' => 'Bar',
401
            'fields' => [
402
                'str' => ['type' => Type::string()],
403
                'int' => ['type' => Type::int()]
404
            ],
405
            'interfaces' => [$fooType, $baazType]
406
        ]);
407
408
        $query = new ObjectType([
409
            'name' => 'Query',
410
            'fields' => ['bar' => ['type' => $barType]]
411
        ]);
412
413
        $schema = new Schema([
414
            'query' => $query,
415
            'types' => [$barType]
416
        ]);
417
        $output = $this->printForTest($schema);
418
        $this->assertEquals('
419
interface Baaz {
420
  int: Int
421
}
422
423
type Bar implements Foo & Baaz {
424
  str: String
425
  int: Int
426
}
427
428
interface Foo {
429
  str: String
430
}
431
432
type Query {
433
  bar: Bar
434
}
435
', $output);
436
    }
437
438
    /**
439
     * @it Print Unions
440
     */
441
    public function testPrintUnions()
442
    {
443
        $fooType = new ObjectType([
444
            'name' => 'Foo',
445
            'fields' => ['bool' => ['type' => Type::boolean()]]
446
        ]);
447
448
        $barType = new ObjectType([
449
            'name' => 'Bar',
450
            'fields' => ['str' => ['type' => Type::string()]]
451
        ]);
452
453
        $singleUnion = new UnionType([
454
            'name' => 'SingleUnion',
455
            'types' => [$fooType]
456
        ]);
457
458
        $multipleUnion = new UnionType([
459
            'name' => 'MultipleUnion',
460
            'types' => [$fooType, $barType]
461
        ]);
462
463
        $query = new ObjectType([
464
            'name' => 'Query',
465
            'fields' => [
466
                'single' => ['type' => $singleUnion],
467
                'multiple' => ['type' => $multipleUnion]
468
            ]
469
        ]);
470
471
        $schema = new Schema(['query' => $query]);
472
        $output = $this->printForTest($schema);
473
        $this->assertEquals('
474
type Bar {
475
  str: String
476
}
477
478
type Foo {
479
  bool: Boolean
480
}
481
482
union MultipleUnion = Foo | Bar
483
484
type Query {
485
  single: SingleUnion
486
  multiple: MultipleUnion
487
}
488
489
union SingleUnion = Foo
490
', $output);
491
    }
492
493
    /**
494
     * @it Print Input Type
495
     */
496
    public function testInputType()
497
    {
498
        $inputType = new InputObjectType([
499
            'name' => 'InputType',
500
            'fields' => ['int' => ['type' => Type::int()]]
501
        ]);
502
503
        $query = new ObjectType([
504
            'name' => 'Query',
505
            'fields' => [
506
                'str' => [
507
                    'type' => Type::string(),
508
                    'args' => ['argOne' => ['type' => $inputType]]
509
                ]
510
            ]
511
        ]);
512
513
        $schema = new Schema(['query' => $query]);
514
        $output = $this->printForTest($schema);
515
        $this->assertEquals('
516
input InputType {
517
  int: Int
518
}
519
520
type Query {
521
  str(argOne: InputType): String
522
}
523
', $output);
524
    }
525
526
    /**
527
     * @it Custom Scalar
528
     */
529
    public function testCustomScalar()
530
    {
531
        $oddType = new CustomScalarType([
532
            'name' => 'Odd',
533
            'serialize' => function($value) {
534
                return $value % 2 === 1 ? $value : null;
535
            }
536
        ]);
537
538
        $query = new ObjectType([
539
            'name' => 'Query',
540
            'fields' => [
541
                'odd' => ['type' => $oddType]
542
            ]
543
        ]);
544
545
        $schema = new Schema(['query' => $query]);
546
        $output = $this->printForTest($schema);
547
        $this->assertEquals('
548
scalar Odd
549
550
type Query {
551
  odd: Odd
552
}
553
', $output);
554
    }
555
556
    /**
557
     * @it Enum
558
     */
559
    public function testEnum()
560
    {
561
        $RGBType = new EnumType([
562
            'name' => 'RGB',
563
            'values' => [
564
                'RED' => ['value' => 0],
565
                'GREEN' => ['value' => 1],
566
                'BLUE' => ['value' => 2]
567
            ]
568
        ]);
569
570
        $query = new ObjectType([
571
            'name' => 'Query',
572
            'fields' => [
573
                'rgb' => ['type' => $RGBType]
574
            ]
575
        ]);
576
577
        $schema = new Schema(['query' => $query]);
578
        $output = $this->printForTest($schema);
579
        $this->assertEquals('
580
type Query {
581
  rgb: RGB
582
}
583
584
enum RGB {
585
  RED
586
  GREEN
587
  BLUE
588
}
589
', $output);
590
    }
591
592
    /**
593
     * @it Prints custom directives
594
     */
595
    public function testPrintsCustomDirectives()
596
    {
597
        $query = new ObjectType([
598
            'name' => 'Query',
599
            'fields' => [
600
                'field' => ['type' => Type::string()],
601
            ]
602
        ]);
603
604
        $customDirectives = new Directive([
605
            'name' => 'customDirective',
606
            'locations' => [
607
                DirectiveLocation::FIELD
608
            ]
609
        ]);
610
611
        $schema = new Schema([
612
            'query' => $query,
613
            'directives' => [$customDirectives],
614
        ]);
615
616
        $output = $this->printForTest($schema);
617
        $this->assertEquals('
618
directive @customDirective on FIELD
619
620
type Query {
621
  field: String
622
}
623
', $output);
624
    }
625
626
    /**
627
     * @it One-line prints a short description
628
     */
629
    public function testOneLinePrintsAShortDescription()
630
    {
631
        $description = 'This field is awesome';
632
        $output = $this->printSingleFieldSchema([
633
            "type" => Type::string(),
634
            "description" => $description
635
        ]);
636
637
        $this->assertEquals('
638
type Query {
639
  """This field is awesome"""
640
  singleField: String
641
}
642
', $output);
643
644
        $recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
645
        $recreatedField = $recreatedRoot->getFields()['singleField'];
0 ignored issues
show
Bug introduced by
The method getFields() does not exist on GraphQL\Type\Definition\Type. It seems like you code against a sub-type of GraphQL\Type\Definition\Type such as GraphQL\Type\Definition\InterfaceType or GraphQL\Type\Definition\ObjectType or GraphQL\Type\Definition\InputObjectType. ( Ignorable by Annotation )

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

645
        $recreatedField = $recreatedRoot->/** @scrutinizer ignore-call */ getFields()['singleField'];
Loading history...
646
        $this->assertEquals($description, $recreatedField->description);
647
    }
648
649
    /**
650
     * @it Does not one-line print a description that ends with a quote
651
     */
652
    public function testDoesNotOneLinePrintADescriptionThatEndsWithAQuote()
653
    {
654
        $description = 'This field is "awesome"';
655
        $output = $this->printSingleFieldSchema([
656
            "type" => Type::string(),
657
            "description" => $description
658
        ]);
659
660
        $this->assertEquals('
661
type Query {
662
  """
663
  This field is "awesome"
664
  """
665
  singleField: String
666
}
667
', $output);
668
669
        $recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
670
        $recreatedField = $recreatedRoot->getFields()['singleField'];
671
        $this->assertEquals($description, $recreatedField->description);
672
    }
673
674
    /**
675
     * @it Preserves leading spaces when printing a description
676
     */
677
    public function testPReservesLeadingSpacesWhenPrintingADescription()
678
    {
679
        $description = '    This field is "awesome"';
680
        $output = $this->printSingleFieldSchema([
681
            "type" => Type::string(),
682
            "description" => $description
683
        ]);
684
685
        $this->assertEquals('
686
type Query {
687
  """    This field is "awesome"
688
  """
689
  singleField: String
690
}
691
', $output);
692
693
        $recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
694
        $recreatedField = $recreatedRoot->getFields()['singleField'];
695
        $this->assertEquals($description, $recreatedField->description);
696
    }
697
698
    /**
699
     * @it Print Introspection Schema
700
     */
701
    public function testPrintIntrospectionSchema()
702
    {
703
        $query = new ObjectType([
704
            'name' => 'Query',
705
            'fields' => [
706
                'onlyField' => ['type' => Type::string()]
707
            ]
708
        ]);
709
710
        $schema = new Schema(['query' => $query]);
711
        $output = SchemaPrinter::printIntrosepctionSchema($schema);
712
        $introspectionSchema = <<<'EOT'
713
"""
714
Directs the executor to include this field or fragment only when the `if` argument is true.
715
"""
716
directive @include(
717
  """Included when true."""
718
  if: Boolean!
719
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
720
721
"""
722
Directs the executor to skip this field or fragment when the `if` argument is true.
723
"""
724
directive @skip(
725
  """Skipped when true."""
726
  if: Boolean!
727
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
728
729
"""Marks an element of a GraphQL schema as no longer supported."""
730
directive @deprecated(
731
  """
732
  Explains why this element was deprecated, usually also including a suggestion
733
  for how to access supported similar data. Formatted in
734
  [Markdown](https://daringfireball.net/projects/markdown/).
735
  """
736
  reason: String = "No longer supported"
737
) on FIELD_DEFINITION | ENUM_VALUE
738
739
"""
740
A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
741
742
In some cases, you need to provide options to alter GraphQL's execution behavior
743
in ways field arguments will not suffice, such as conditionally including or
744
skipping a field. Directives provide this by describing additional information
745
to the executor.
746
"""
747
type __Directive {
748
  name: String!
749
  description: String
750
  locations: [__DirectiveLocation!]!
751
  args: [__InputValue!]!
752
  onOperation: Boolean! @deprecated(reason: "Use `locations`.")
753
  onFragment: Boolean! @deprecated(reason: "Use `locations`.")
754
  onField: Boolean! @deprecated(reason: "Use `locations`.")
755
}
756
757
"""
758
A Directive can be adjacent to many parts of the GraphQL language, a
759
__DirectiveLocation describes one such possible adjacencies.
760
"""
761
enum __DirectiveLocation {
762
  """Location adjacent to a query operation."""
763
  QUERY
764
765
  """Location adjacent to a mutation operation."""
766
  MUTATION
767
768
  """Location adjacent to a subscription operation."""
769
  SUBSCRIPTION
770
771
  """Location adjacent to a field."""
772
  FIELD
773
774
  """Location adjacent to a fragment definition."""
775
  FRAGMENT_DEFINITION
776
777
  """Location adjacent to a fragment spread."""
778
  FRAGMENT_SPREAD
779
780
  """Location adjacent to an inline fragment."""
781
  INLINE_FRAGMENT
782
783
  """Location adjacent to a schema definition."""
784
  SCHEMA
785
786
  """Location adjacent to a scalar definition."""
787
  SCALAR
788
789
  """Location adjacent to an object type definition."""
790
  OBJECT
791
792
  """Location adjacent to a field definition."""
793
  FIELD_DEFINITION
794
795
  """Location adjacent to an argument definition."""
796
  ARGUMENT_DEFINITION
797
798
  """Location adjacent to an interface definition."""
799
  INTERFACE
800
801
  """Location adjacent to a union definition."""
802
  UNION
803
804
  """Location adjacent to an enum definition."""
805
  ENUM
806
807
  """Location adjacent to an enum value definition."""
808
  ENUM_VALUE
809
810
  """Location adjacent to an input object type definition."""
811
  INPUT_OBJECT
812
813
  """Location adjacent to an input object field definition."""
814
  INPUT_FIELD_DEFINITION
815
}
816
817
"""
818
One possible value for a given Enum. Enum values are unique values, not a
819
placeholder for a string or numeric value. However an Enum value is returned in
820
a JSON response as a string.
821
"""
822
type __EnumValue {
823
  name: String!
824
  description: String
825
  isDeprecated: Boolean!
826
  deprecationReason: String
827
}
828
829
"""
830
Object and Interface types are described by a list of Fields, each of which has
831
a name, potentially a list of arguments, and a return type.
832
"""
833
type __Field {
834
  name: String!
835
  description: String
836
  args: [__InputValue!]!
837
  type: __Type!
838
  isDeprecated: Boolean!
839
  deprecationReason: String
840
}
841
842
"""
843
Arguments provided to Fields or Directives and the input fields of an
844
InputObject are represented as Input Values which describe their type and
845
optionally a default value.
846
"""
847
type __InputValue {
848
  name: String!
849
  description: String
850
  type: __Type!
851
852
  """
853
  A GraphQL-formatted string representing the default value for this input value.
854
  """
855
  defaultValue: String
856
}
857
858
"""
859
A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all
860
available types and directives on the server, as well as the entry points for
861
query, mutation, and subscription operations.
862
"""
863
type __Schema {
864
  """A list of all types supported by this server."""
865
  types: [__Type!]!
866
867
  """The type that query operations will be rooted at."""
868
  queryType: __Type!
869
870
  """
871
  If this server supports mutation, the type that mutation operations will be rooted at.
872
  """
873
  mutationType: __Type
874
875
  """
876
  If this server support subscription, the type that subscription operations will be rooted at.
877
  """
878
  subscriptionType: __Type
879
880
  """A list of all directives supported by this server."""
881
  directives: [__Directive!]!
882
}
883
884
"""
885
The fundamental unit of any GraphQL Schema is the type. There are many kinds of
886
types in GraphQL as represented by the `__TypeKind` enum.
887
888
Depending on the kind of a type, certain fields describe information about that
889
type. Scalar types provide no information beyond a name and description, while
890
Enum types provide their values. Object and Interface types provide the fields
891
they describe. Abstract types, Union and Interface, provide the Object types
892
possible at runtime. List and NonNull types compose other types.
893
"""
894
type __Type {
895
  kind: __TypeKind!
896
  name: String
897
  description: String
898
  fields(includeDeprecated: Boolean = false): [__Field!]
899
  interfaces: [__Type!]
900
  possibleTypes: [__Type!]
901
  enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
902
  inputFields: [__InputValue!]
903
  ofType: __Type
904
}
905
906
"""An enum describing what kind of type a given `__Type` is."""
907
enum __TypeKind {
908
  """Indicates this type is a scalar."""
909
  SCALAR
910
911
  """
912
  Indicates this type is an object. `fields` and `interfaces` are valid fields.
913
  """
914
  OBJECT
915
916
  """
917
  Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.
918
  """
919
  INTERFACE
920
921
  """Indicates this type is a union. `possibleTypes` is a valid field."""
922
  UNION
923
924
  """Indicates this type is an enum. `enumValues` is a valid field."""
925
  ENUM
926
927
  """
928
  Indicates this type is an input object. `inputFields` is a valid field.
929
  """
930
  INPUT_OBJECT
931
932
  """Indicates this type is a list. `ofType` is a valid field."""
933
  LIST
934
935
  """Indicates this type is a non-null. `ofType` is a valid field."""
936
  NON_NULL
937
}
938
939
EOT;
940
        $this->assertEquals($introspectionSchema, $output);
941
    }
942
943
    /**
944
     * @it Print Introspection Schema with comment descriptions
945
     */
946
    public function testPrintIntrospectionSchemaWithCommentDescriptions()
947
    {
948
        $query = new ObjectType([
949
            'name' => 'Query',
950
            'fields' => [
951
                'onlyField' => ['type' => Type::string()]
952
            ]
953
        ]);
954
955
        $schema = new Schema(['query' => $query]);
956
        $output = SchemaPrinter::printIntrosepctionSchema($schema, [
957
            'commentDescriptions' => true
958
        ]);
959
        $introspectionSchema = <<<'EOT'
960
# Directs the executor to include this field or fragment only when the `if` argument is true.
961
directive @include(
962
  # Included when true.
963
  if: Boolean!
964
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
965
966
# Directs the executor to skip this field or fragment when the `if` argument is true.
967
directive @skip(
968
  # Skipped when true.
969
  if: Boolean!
970
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
971
972
# Marks an element of a GraphQL schema as no longer supported.
973
directive @deprecated(
974
  # Explains why this element was deprecated, usually also including a suggestion
975
  # for how to access supported similar data. Formatted in
976
  # [Markdown](https://daringfireball.net/projects/markdown/).
977
  reason: String = "No longer supported"
978
) on FIELD_DEFINITION | ENUM_VALUE
979
980
# A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
981
#
982
# In some cases, you need to provide options to alter GraphQL's execution behavior
983
# in ways field arguments will not suffice, such as conditionally including or
984
# skipping a field. Directives provide this by describing additional information
985
# to the executor.
986
type __Directive {
987
  name: String!
988
  description: String
989
  locations: [__DirectiveLocation!]!
990
  args: [__InputValue!]!
991
  onOperation: Boolean! @deprecated(reason: "Use `locations`.")
992
  onFragment: Boolean! @deprecated(reason: "Use `locations`.")
993
  onField: Boolean! @deprecated(reason: "Use `locations`.")
994
}
995
996
# A Directive can be adjacent to many parts of the GraphQL language, a
997
# __DirectiveLocation describes one such possible adjacencies.
998
enum __DirectiveLocation {
999
  # Location adjacent to a query operation.
1000
  QUERY
1001
1002
  # Location adjacent to a mutation operation.
1003
  MUTATION
1004
1005
  # Location adjacent to a subscription operation.
1006
  SUBSCRIPTION
1007
1008
  # Location adjacent to a field.
1009
  FIELD
1010
1011
  # Location adjacent to a fragment definition.
1012
  FRAGMENT_DEFINITION
1013
1014
  # Location adjacent to a fragment spread.
1015
  FRAGMENT_SPREAD
1016
1017
  # Location adjacent to an inline fragment.
1018
  INLINE_FRAGMENT
1019
1020
  # Location adjacent to a schema definition.
1021
  SCHEMA
1022
1023
  # Location adjacent to a scalar definition.
1024
  SCALAR
1025
1026
  # Location adjacent to an object type definition.
1027
  OBJECT
1028
1029
  # Location adjacent to a field definition.
1030
  FIELD_DEFINITION
1031
1032
  # Location adjacent to an argument definition.
1033
  ARGUMENT_DEFINITION
1034
1035
  # Location adjacent to an interface definition.
1036
  INTERFACE
1037
1038
  # Location adjacent to a union definition.
1039
  UNION
1040
1041
  # Location adjacent to an enum definition.
1042
  ENUM
1043
1044
  # Location adjacent to an enum value definition.
1045
  ENUM_VALUE
1046
1047
  # Location adjacent to an input object type definition.
1048
  INPUT_OBJECT
1049
1050
  # Location adjacent to an input object field definition.
1051
  INPUT_FIELD_DEFINITION
1052
}
1053
1054
# One possible value for a given Enum. Enum values are unique values, not a
1055
# placeholder for a string or numeric value. However an Enum value is returned in
1056
# a JSON response as a string.
1057
type __EnumValue {
1058
  name: String!
1059
  description: String
1060
  isDeprecated: Boolean!
1061
  deprecationReason: String
1062
}
1063
1064
# Object and Interface types are described by a list of Fields, each of which has
1065
# a name, potentially a list of arguments, and a return type.
1066
type __Field {
1067
  name: String!
1068
  description: String
1069
  args: [__InputValue!]!
1070
  type: __Type!
1071
  isDeprecated: Boolean!
1072
  deprecationReason: String
1073
}
1074
1075
# Arguments provided to Fields or Directives and the input fields of an
1076
# InputObject are represented as Input Values which describe their type and
1077
# optionally a default value.
1078
type __InputValue {
1079
  name: String!
1080
  description: String
1081
  type: __Type!
1082
1083
  # A GraphQL-formatted string representing the default value for this input value.
1084
  defaultValue: String
1085
}
1086
1087
# A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all
1088
# available types and directives on the server, as well as the entry points for
1089
# query, mutation, and subscription operations.
1090
type __Schema {
1091
  # A list of all types supported by this server.
1092
  types: [__Type!]!
1093
1094
  # The type that query operations will be rooted at.
1095
  queryType: __Type!
1096
1097
  # If this server supports mutation, the type that mutation operations will be rooted at.
1098
  mutationType: __Type
1099
1100
  # If this server support subscription, the type that subscription operations will be rooted at.
1101
  subscriptionType: __Type
1102
1103
  # A list of all directives supported by this server.
1104
  directives: [__Directive!]!
1105
}
1106
1107
# The fundamental unit of any GraphQL Schema is the type. There are many kinds of
1108
# types in GraphQL as represented by the `__TypeKind` enum.
1109
#
1110
# Depending on the kind of a type, certain fields describe information about that
1111
# type. Scalar types provide no information beyond a name and description, while
1112
# Enum types provide their values. Object and Interface types provide the fields
1113
# they describe. Abstract types, Union and Interface, provide the Object types
1114
# possible at runtime. List and NonNull types compose other types.
1115
type __Type {
1116
  kind: __TypeKind!
1117
  name: String
1118
  description: String
1119
  fields(includeDeprecated: Boolean = false): [__Field!]
1120
  interfaces: [__Type!]
1121
  possibleTypes: [__Type!]
1122
  enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
1123
  inputFields: [__InputValue!]
1124
  ofType: __Type
1125
}
1126
1127
# An enum describing what kind of type a given `__Type` is.
1128
enum __TypeKind {
1129
  # Indicates this type is a scalar.
1130
  SCALAR
1131
1132
  # Indicates this type is an object. `fields` and `interfaces` are valid fields.
1133
  OBJECT
1134
1135
  # Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.
1136
  INTERFACE
1137
1138
  # Indicates this type is a union. `possibleTypes` is a valid field.
1139
  UNION
1140
1141
  # Indicates this type is an enum. `enumValues` is a valid field.
1142
  ENUM
1143
1144
  # Indicates this type is an input object. `inputFields` is a valid field.
1145
  INPUT_OBJECT
1146
1147
  # Indicates this type is a list. `ofType` is a valid field.
1148
  LIST
1149
1150
  # Indicates this type is a non-null. `ofType` is a valid field.
1151
  NON_NULL
1152
}
1153
1154
EOT;
1155
        $this->assertEquals($introspectionSchema, $output);
1156
    }
1157
}
1158