Completed
Push — master ( a7a918...731c42 )
by Alexandr
03:36
created

ProcessorTest::testContainer()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 16
nc 1
nop 0
1
<?php
2
/*
3
 * This file is a part of GraphQL project.
4
 *
5
 * @author Alexandr Viniychuk <[email protected]>
6
 * created: 11:02 PM 5/13/16
7
 */
8
9
namespace Youshido\Tests\Schema;
10
11
12
use Youshido\GraphQL\Execution\Container\Container;
13
use Youshido\GraphQL\Execution\Context\ExecutionContext;
14
use Youshido\GraphQL\Execution\Processor;
15
use Youshido\GraphQL\Execution\ResolveInfo;
16
use Youshido\GraphQL\Execution\Visitor\MaxComplexityQueryVisitor;
17
use Youshido\GraphQL\Field\Field;
18
use Youshido\GraphQL\Schema\Schema;
19
use Youshido\GraphQL\Type\Enum\EnumType;
20
use Youshido\GraphQL\Type\ListType\ListType;
21
use Youshido\GraphQL\Type\NonNullType;
22
use Youshido\GraphQL\Type\Object\ObjectType;
23
use Youshido\GraphQL\Type\Scalar\BooleanType;
24
use Youshido\GraphQL\Type\Scalar\IdType;
25
use Youshido\GraphQL\Type\Scalar\IntType;
26
use Youshido\GraphQL\Type\Scalar\StringType;
27
use Youshido\GraphQL\Type\Union\UnionType;
28
use Youshido\Tests\DataProvider\TestEmptySchema;
29
use Youshido\Tests\DataProvider\TestEnumType;
30
use Youshido\Tests\DataProvider\TestInterfaceType;
31
use Youshido\Tests\DataProvider\TestObjectType;
32
use Youshido\Tests\DataProvider\TestSchema;
33
34
class ProcessorTest extends \PHPUnit_Framework_TestCase
35
{
36
37
    private $_counter = 0;
38
39
    public function testInit()
40
    {
41
        $processor = new Processor(new TestEmptySchema());
42
        $this->assertEquals([['message' => 'Schema has to have fields']], $processor->getExecutionContext()->getErrorsArray());
43
    }
44
45
    public function testEmptyQueries()
46
    {
47
        $processor = new Processor(new TestSchema());
48
        $processor->processPayload('');
49
        $this->assertEquals(['errors' => [
50
            ['message' => 'Must provide an operation.']
51
        ]], $processor->getResponseData());
52
53
        $processor->getExecutionContext()->clearErrors();
54
        $processor->processPayload('{ me { name } }');
55
        $this->assertEquals(['data' => [
56
            'me' => ['name' => 'John']
57
        ]], $processor->getResponseData());
58
59
    }
60
61
    public function testNestedVariables()
62
    {
63
        $processor    = new Processor(new TestSchema());
64
        $noArgsQuery  = '{ me { echo(value:"foo") } }';
65
        $expectedData = ['data' => ['me' => ['echo' => 'foo']]];
66
        $processor->processPayload($noArgsQuery, ['value' => 'foo']);
67
        $this->assertEquals($expectedData, $processor->getResponseData());
68
69
        $parameterizedFieldQuery =
70
            'query nestedFieldQuery($value:String!){
71
          me {
72
            echo(value:$value)
73
          }
74
        }';
75
        $processor->processPayload($parameterizedFieldQuery, ['value' => 'foo']);
76
        $this->assertEquals($expectedData, $processor->getResponseData());
77
78
        $parameterizedQueryQuery =
79
            'query nestedQueryQuery($value:Int){
80
          me {
81
            location(noop:$value) {
82
              address
83
            }
84
          }
85
        }';
86
        $processor->processPayload($parameterizedQueryQuery, ['value' => 1]);
87
        $this->assertArrayNotHasKey('errors', $processor->getResponseData());
88
    }
89
90 View Code Duplication
    public function testListNullResponse()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
91
    {
92
        $processor = new Processor(new Schema([
93
            'query' => new ObjectType([
94
                'name'   => 'RootQuery',
95
                'fields' => [
96
                    'list' => [
97
                        'type'    => new ListType(new StringType()),
98
                        'resolve' => function () {
99
                            return null;
100
                        }
101
                    ]
102
                ]
103
            ])
104
        ]));
105
        $data      = $processor->processPayload(' { list }')->getResponseData();
106
        $this->assertEquals(['data' => ['list' => null]], $data);
107
    }
108
109
110 View Code Duplication
    public function testSubscriptionNullResponse()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
111
    {
112
        $processor = new Processor(new Schema([
113
            'query' => new ObjectType([
114
                'name'   => 'RootQuery',
115
                'fields' => [
116
                    'list' => [
117
                        'type'    => new ListType(new StringType()),
118
                        'resolve' => function () {
119
                            return null;
120
                        }
121
                    ]
122
                ]
123
            ])
124
        ]));
125
        $data      = $processor->processPayload(' { __schema { subscriptionType { name } } }')->getResponseData();
126
        $this->assertEquals(['data' => ['__schema' => ['subscriptionType' => null]]], $data);
127
    }
128
129
    public function testSchemaOperations()
130
    {
131
        $schema    = new Schema([
132
            'query' => new ObjectType([
133
                'name'   => 'RootQuery',
134
                'fields' => [
135
                    'me'                => [
136
                        'type'    => new ObjectType([
137
                            'name'   => 'User',
138
                            'fields' => [
139
                                'firstName' => [
140
                                    'type'    => new StringType(),
141
                                    'args'    => [
142
                                        'shorten' => new BooleanType()
143
                                    ],
144
                                    'resolve' => function ($value, $args) {
145
                                        return empty($args['shorten']) ? $value['firstName'] : $value['firstName'];
146
                                    }
147
                                ],
148
                                'id_alias'  => [
149
                                    'type'    => new IdType(),
150
                                    'resolve' => function ($value) {
151
                                        return $value['id'];
152
                                    }
153
                                ],
154
                                'lastName'  => new StringType(),
155
                                'code'      => new StringType(),
156
                            ]
157
                        ]),
158
                        'resolve' => function ($value, $args) {
159
                            $data = ['id' => '123', 'firstName' => 'John', 'code' => '007'];
160
                            if (!empty($args['upper'])) {
161
                                foreach ($data as $key => $value) {
162
                                    $data[$key] = strtoupper($value);
163
                                }
164
                            }
165
166
                            return $data;
167
                        },
168
                        'args'    => [
169
                            'upper' => [
170
                                'type'    => new BooleanType(),
171
                                'default' => false
172
                            ]
173
                        ]
174
                    ],
175
                    'randomUser'        => [
176
                        'type'    => new TestObjectType(),
177
                        'resolve' => function () {
178
                            return ['invalidField' => 'John'];
179
                        }
180
                    ],
181
                    'invalidValueQuery' => [
182
                        'type'    => new TestObjectType(),
183
                        'resolve' => function () {
184
                            return 'stringValue';
185
                        }
186
                    ],
187
                    'labels'            => [
188
                        'type'    => new ListType(new StringType()),
189
                        'resolve' => function () {
190
                            return ['one', 'two'];
191
                        }
192
                    ]
193
                ],
194
            ])
195
        ]);
196
        $processor = new Processor($schema);
197
198
        $processor->processPayload('{ me { firstName } }');
199
        $this->assertEquals(['data' => ['me' => ['firstName' => 'John']]], $processor->getResponseData());
200
201
        $processor->processPayload('{ me { id_alias } }');
202
        $this->assertEquals(['data' => ['me' => ['id_alias' => '123']]], $processor->getResponseData());
203
204
        $processor->processPayload('{ me { firstName, lastName } }');
205
        $this->assertEquals(['data' => ['me' => ['firstName' => 'John', 'lastName' => null]]], $processor->getResponseData());
206
207
        $processor->processPayload('{ me { code } }');
208
        $this->assertEquals(['data' => ['me' => ['code' => 7]]], $processor->getResponseData());
209
210
        $processor->processPayload('{ me(upper:true) { firstName } }');
211
        $this->assertEquals(['data' => ['me' => ['firstName' => 'JOHN']]], $processor->getResponseData());
212
213
        $processor->processPayload('{ labels }');
214
        $this->assertEquals(['data' => ['labels' => ['one', 'two']]], $processor->getResponseData());
215
216
        $schema->getMutationType()
217
               ->addField(new Field([
218
                   'name'    => 'increaseCounter',
219
                   'type'    => new IntType(),
220
                   'resolve' => function ($value, $args, ResolveInfo $info) {
0 ignored issues
show
Unused Code introduced by
The parameter $info is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
221
                       return $this->_counter += $args['amount'];
222
                   },
223
                   'args'    => [
224
                       'amount' => [
225
                           'type'    => new IntType(),
226
                           'default' => 1
227
                       ]
228
                   ]
229
               ]))->addField(new Field([
230
                'name'    => 'invalidResolveTypeMutation',
231
                'type'    => new NonNullType(new IntType()),
232
                'resolve' => function () {
233
                    return null;
234
                }
235
            ]))->addField(new Field([
236
                'name'    => 'interfacedMutation',
237
                'type'    => new TestInterfaceType(),
238
                'resolve' => function () {
239
                    return ['name' => 'John'];
240
                }
241
            ]));
242
        $processor->processPayload('mutation { increaseCounter }');
243
        $this->assertEquals(['data' => ['increaseCounter' => 1]], $processor->getResponseData());
244
245
        $processor->processPayload('mutation { invalidMutation }');
246
        $this->assertEquals(['errors' => [['message' => 'Field "invalidMutation" not found in type "RootSchemaMutation"']]], $processor->getResponseData());
247
        $processor->getExecutionContext()->clearErrors();
248
249
        $processor->processPayload('mutation { increaseCounter(noArg: 2) }');
250
        $this->assertEquals(['errors' => [['message' => 'Unknown argument "noArg" on field "increaseCounter"']]], $processor->getResponseData());
251
        $processor->getExecutionContext()->clearErrors();
252
253
        $processor->processPayload('mutation { increaseCounter(amount: 2) { invalidProp } }');
254
        $this->assertEquals(['errors' => [['message' => 'Fields are not found in query "increaseCounter"']], 'data' => ['increaseCounter' => null]], $processor->getResponseData());
255
        $processor->getExecutionContext()->clearErrors();
256
257
        $processor->processPayload('mutation { increaseCounter(amount: 2) }');
258
        $this->assertEquals(['data' => ['increaseCounter' => 5]], $processor->getResponseData());
259
260
        $processor->processPayload('{ invalidQuery }');
261
        $this->assertEquals(['errors' => [['message' => 'Field "invalidQuery" not found in type "RootQuery"']]], $processor->getResponseData());
262
        $processor->getExecutionContext()->clearErrors();
263
264
        $processor->processPayload('{ invalidValueQuery { id } }');
265
        $this->assertEquals(['errors' => [['message' => 'Not valid value for OBJECT field invalidValueQuery']], 'data' => ['invalidValueQuery' => null]], $processor->getResponseData());
266
        $processor->getExecutionContext()->clearErrors();
267
268
        $processor->processPayload('{ me { firstName(shorten: true), middle }}');
269
        $this->assertEquals(['errors' => [['message' => 'Field "middle" is not found in type "User"']], 'data' => ['me' => null]], $processor->getResponseData());
270
        $processor->getExecutionContext()->clearErrors();
271
272
        $processor->processPayload('{ randomUser { region }}');
273
        $this->assertEquals(['errors' => [['message' => 'Property "region" not found in resolve result']]], $processor->getResponseData());
274
        $processor->getExecutionContext()->clearErrors();
275
276
        $processor->processPayload('mutation { invalidResolveTypeMutation }');
277
        $this->assertEquals(['errors' => [['message' => 'Cannot return null for non-nullable field invalidResolveTypeMutation']], 'data' => ['invalidResolveTypeMutation' => null]], $processor->getResponseData());
278
        $processor->getExecutionContext()->clearErrors();
279
280
        $processor->processPayload('mutation { user:interfacedMutation { name }  }');
281
        $this->assertEquals(['data' => ['user' => ['name' => 'John']]], $processor->getResponseData());
282
    }
283
284
    public function testEnumType()
285
    {
286
        $processor = new Processor(new Schema([
287
            'query' => new ObjectType([
288
                'name'   => 'RootQuery',
289
                'fields' => [
290
                    'test' => [
291
                        'args'    => [
292
                            'argument1' => new NonNullType(new EnumType([
293
                                'name'   => 'TestEnumType',
294
                                'values' => [
295
                                    [
296
                                        'name'  => 'VALUE1',
297
                                        'value' => 'val1'
298
                                    ],
299
                                    [
300
                                        'name'  => 'VALUE2',
301
                                        'value' => 'val2'
302
                                    ]
303
                                ]
304
                            ]))
305
                        ],
306
                        'type'    => new StringType(),
307
                        'resolve' => function ($value, $args) {
308
                            return $args['argument1'];
309
                        }
310
                    ]
311
                ]
312
            ])
313
        ]));
314
315
        $processor->processPayload('{ test }');
316
        $response = $processor->getResponseData();
317
        $this->assertEquals(['errors' => [['message' => 'Require "argument1" arguments to query "test"']]], $response);
318
        $processor->getExecutionContext()->clearErrors();
319
320
        $processor->processPayload('{ alias: test() }');
321
        $response = $processor->getResponseData();
322
        $this->assertEquals(['errors' => [['message' => 'Require "argument1" arguments to query "test"']]], $response);
323
        $processor->getExecutionContext()->clearErrors();
324
325
        $processor->processPayload('{ alias: test(argument1: VALUE4) }');
326
        $response = $processor->getResponseData();
327
        $this->assertEquals(['errors' => [['message' => 'Not valid type for argument "argument1" in query "test"']]], $response);
328
        $processor->getExecutionContext()->clearErrors();
329
330
        $processor->processPayload('{ alias: test(argument1: VALUE1) }');
331
        $response = $processor->getResponseData();
332
        $this->assertEquals(['data' => ['alias' => 'val1']], $response);
333
    }
334
335
    public function testListEnumsSchemaOperations()
336
    {
337
        $processor = new Processor(new Schema([
338
            'query' => new ObjectType([
339
                'name'   => 'RootQuery',
340
                'fields' => [
341
                    'listQuery'                 => [
342
                        'type'    => new ListType(new TestEnumType()),
343
                        'resolve' => function () {
344
                            return 'invalid list';
345
                        }
346
                    ],
347
                    'listEnumQuery'             => [
348
                        'type'    => new ListType(new TestEnumType()),
349
                        'resolve' => function () {
350
                            return ['invalid enum'];
351
                        }
352
                    ],
353
                    'invalidEnumQuery'          => [
354
                        'type'    => new TestEnumType(),
355
                        'resolve' => function () {
356
                            return 'invalid enum';
357
                        }
358
                    ],
359
                    'enumQuery'                 => [
360
                        'type'    => new TestEnumType(),
361
                        'resolve' => function () {
362
                            return 1;
363
                        }
364
                    ],
365
                    'invalidNonNullQuery'       => [
366
                        'type'    => new NonNullType(new IntType()),
367
                        'resolve' => function () {
368
                            return null;
369
                        }
370
                    ],
371
                    'invalidNonNullInsideQuery' => [
372
                        'type'    => new NonNullType(new IntType()),
373
                        'resolve' => function () {
374
                            return 'hello';
375
                        }
376
                    ],
377
                    'objectQuery'               => [
378
                        'type'    => new TestObjectType(),
379
                        'resolve' => function () {
380
                            return ['name' => 'John'];
381
                        }
382
                    ],
383
                    'deepObjectQuery'           => [
384
                        'type'    => new ObjectType([
385
                            'name'   => 'deepObject',
386
                            'fields' => [
387
                                'object' => new TestObjectType(),
388
                                'enum'   => new TestEnumType(),
389
                            ],
390
                        ]),
391
                        'resolve' => function () {
392
                            return [
393
                                'object' => [
394
                                    'name' => 'John'
395
                                ],
396
                                'enum'   => 1
397
                            ];
398
                        },
399
                    ],
400
                ]
401
            ])
402
        ]));
403
404
        $processor->processPayload('{ listQuery }');
405
        $this->assertEquals(['errors' => [
406
            ['message' => 'Not valid value for LIST field listQuery']
407
        ], 'data'                     => ['listQuery' => null]], $processor->getResponseData());
408
        $processor->getExecutionContext()->clearErrors();
409
410
        $processor->processPayload('{ listEnumQuery }');
411
        $this->assertEquals(['errors' => [
412
            ['message' => 'Not valid resolve value in listEnumQuery field']
413
        ], 'data'                     => ['listEnumQuery' => [null]]], $processor->getResponseData());
414
        $processor->getExecutionContext()->clearErrors();
415
416
        $processor->processPayload('{ invalidEnumQuery }');
417
        $this->assertEquals(['errors' => [
418
            ['message' => 'Not valid value for ENUM field invalidEnumQuery']
419
        ], 'data'                     => ['invalidEnumQuery' => null]], $processor->getResponseData());
420
        $processor->getExecutionContext()->clearErrors();
421
422
        $processor->processPayload('{ enumQuery }');
423
        $this->assertEquals(['data' => ['enumQuery' => 'FINISHED']], $processor->getResponseData());
424
425
        $processor->processPayload('{ invalidNonNullQuery }');
426
        $this->assertEquals(['errors' => [
427
            ['message' => 'Cannot return null for non-nullable field invalidNonNullQuery']
428
        ], 'data'                     => ['invalidNonNullQuery' => null]], $processor->getResponseData());
429
        $processor->getExecutionContext()->clearErrors();
430
431
        $processor->processPayload('{ invalidNonNullInsideQuery }');
432
        $this->assertEquals(['errors' => [
433
            ['message' => 'Not valid value for SCALAR field invalidNonNullInsideQuery']
434
        ], 'data'                     => ['invalidNonNullInsideQuery' => null]], $processor->getResponseData());
435
        $processor->getExecutionContext()->clearErrors();
436
437
        $processor->processPayload('{ test:deepObjectQuery { object { name } } }');
438
        $this->assertEquals(['data' => ['test' => ['object' => ['name' => 'John']]]], $processor->getResponseData());
439
    }
440
441
    public function testTypedFragment()
442
    {
443
444
        $object1 = new ObjectType([
445
            'name'   => 'Object1',
446
            'fields' => [
447
                'id' => ['type' => 'int', 'cost' => 13]
448
            ]
449
        ]);
450
451
        $object2 = new ObjectType([
452
            'name'   => 'Object2',
453
            'fields' => [
454
                'name' => ['type' => 'string']
455
            ]
456
        ]);
457
458
        $object3 = new ObjectType([
459
            'name'   => 'Object3',
460
            'fields' => [
461
                'name' => ['type' => 'string']
462
            ]
463
        ]);
464
465
        $union        = new UnionType([
466
            'name'        => 'TestUnion',
467
            'types'       => [$object1, $object2],
468
            'resolveType' => function ($object) use ($object1, $object2) {
469
                if (isset($object['id'])) {
470
                    return $object1;
471
                }
472
473
                return $object2;
474
            }
475
        ]);
476
        $invalidUnion = new UnionType([
477
            'name'        => 'TestUnion',
478
            'types'       => [$object1, $object2],
479
            'resolveType' => function ($object) use ($object3) {
0 ignored issues
show
Unused Code introduced by
The parameter $object is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
480
                return $object3;
481
            }
482
        ]);
483
        $processor    = new Processor(new Schema([
484
            'query' => new ObjectType([
485
                'name'   => 'RootQuery',
486
                'fields' => [
487
                    'union'        => [
488
                        'type'    => $union,
489
                        'args'    => [
490
                            'type' => ['type' => 'string']
491
                        ],
492
                        'cost'    => 10,
493
                        'resolve' => function ($value, $args) {
494
                            if ($args['type'] == 'object1') {
495
                                return [
496
                                    'id' => 43
497
                                ];
498
                            } else {
499
                                return [
500
                                    'name' => 'name resolved'
501
                                ];
502
                            }
503
                        }
504
                    ],
505
                    'invalidUnion' => [
506
                        'type'    => $invalidUnion,
507
                        'resolve' => function () {
508
                            return ['name' => 'name resolved'];
509
                        }
510
                    ],
511
                ]
512
            ])
513
        ]));
514
        $processor->processPayload('{ union(type: "object1") { ... on Object2 { id } } }');
515
        $this->assertEquals(['data' => ['union' => []]], $processor->getResponseData());
516
517
        $processor->processPayload('{ union(type: "object1") { ... on Object1 { name } } }');
518
        $this->assertEquals([
519
            'data'   => [
520
                'union' => []
521
            ],
522
            'errors' => [
523
                ['message' => 'Field "name" is not found in type "Object1"']
524
            ]
525
        ], $processor->getResponseData());
526
        $processor->getExecutionContext()->clearErrors();
527
528
        $processor->processPayload('{ union(type: "object1") { ... on Object1 { id } } }');
529
        $this->assertEquals(['data' => ['union' => ['id' => 43]]], $processor->getResponseData());
530
531
        $processor->processPayload('{ union(type: "asd") { ... on Object2 { name } } }');
532
        $this->assertEquals(['data' => ['union' => ['name' => 'name resolved']]], $processor->getResponseData());
533
534
        $processor->processPayload('{ invalidUnion { ... on Object2 { name } } }');
535
        $this->assertEquals(['errors' => [['message' => 'Type Object3 not exist in types of Object2']]], $processor->getResponseData());
536
537
        $visitor = new MaxComplexityQueryVisitor(1000); // arbitrarily high cost
538
        $processor->processPayload('{ union(type: "object1") { ... on Object1 { id } } }', [], [$visitor]);
539
        $this->assertEquals(10 + 13, $visitor->getMemo());
540
541
        $visitor = new MaxComplexityQueryVisitor(1000); // arbitrarily high cost
542
        $processor->processPayload('{ union(type: "object1") { ... on Object1 { id }, ... on Object2 { name } } }', [], [$visitor]);
543
        $this->assertEquals(10 + 13 + 1, $visitor->getMemo());
544
545
        // planning phase currently has no knowledge of what types the union will resolve to, this will have the same score as above
546
        $visitor = new MaxComplexityQueryVisitor(1000); // arbitrarily high cost
547
        $processor->processPayload('{ union(type: "object2") { ... on Object1 { id }, ... on Object2 { name } } }', [], [$visitor]);
548
        $this->assertEquals(10 + 13 + 1, $visitor->getMemo());
549
    }
550
551
    public function testContainer()
552
    {
553
        $container = new Container();
554
        $container->set('user', ['name' => 'Alex']);
555
556
        $executionContext = new ExecutionContext(new Schema([
557
            'query' => new ObjectType([
558
                'name'   => 'RootQuery',
559
                'fields' => [
560
                    'currentUser' => [
561
                        'type'    => new StringType(),
562
                        'resolve' => function ($source, $args, ResolveInfo $info) {
563
                            return $info->getContainer()->get('user')['name'];
564
                        }
565
                    ]
566
                ]
567
            ])
568
        ]));
569
        $executionContext->setContainer($container);
570
        $this->assertNotNull($executionContext->getContainer());
571
572
        $processor = new Processor($executionContext->getSchema());
573
        $processor->getExecutionContext()->setContainer($container);
574
575
        $this->assertEquals(['data' => ['currentUser' => 'Alex']], $processor->processPayload('{ currentUser }')->getResponseData());
576
    }
577
578
    public function testComplexityReducer()
579
    {
580
        $schema    = new Schema(
581
            [
582
                'query' => new ObjectType(
583
                    [
584
                        'name'   => 'RootQuery',
585
                        'fields' => [
586
                            'me' => [
587
                                'type'    => new ObjectType(
588
                                    [
589
                                        'name'   => 'User',
590
                                        'fields' => [
591
                                            'firstName' => [
592
                                                'type'    => new StringType(),
593
                                                'args'    => [
594
                                                    'shorten' => new BooleanType()
595
                                                ],
596
                                                'resolve' => function ($value, $args) {
597
                                                    return empty($args['shorten']) ? $value : $value;
598
                                                }
599
                                            ],
600
                                            'lastName'  => new StringType(),
601
                                            'code'      => new StringType(),
602
                                            'likes'     => [
603
                                                'type'    => new IntType(),
604
                                                'cost'    => 10,
605
                                                'resolve' => function () {
606
                                                    return 42;
607
                                                }
608
                                            ]
609
                                        ]
610
                                    ]
611
                                ),
612
                                'cost'    => function ($args, $context, $childCost) {
613
                                    $argsCost = isset($args['cost']) ? $args['cost'] : 1;
614
615
                                    return 1 + $argsCost * $childCost;
616
                                },
617
                                'resolve' => function ($value, $args) {
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
618
                                    $data = ['firstName' => 'John', 'code' => '007'];
619
620
                                    return $data;
621
                                },
622
                                'args'    => [
623
                                    'cost' => [
624
                                        'type'    => new IntType(),
625
                                        'default' => 1
626
                                    ]
627
                                ]
628
                            ]
629
                        ]
630
                    ]
631
                )
632
            ]
633
        );
634
        $processor = new Processor($schema);
635
636
        $processor->setMaxComplexity(10);
637
638
        $processor->processPayload('{ me { firstName, lastName } }');
639
        $this->assertArrayNotHasKey('error', $processor->getResponseData());
640
641
        $processor->processPayload('{ me { } }');
642
        $this->assertEquals(['errors' => [['message' => 'You have to specify fields for "me"']]], $processor->getResponseData());
643
        $processor->getExecutionContext()->clearErrors();
644
645
646
        $processor->processPayload('{ me { firstName, likes } }');
647
        $this->assertEquals(['errors' => [['message' => 'query exceeded max allowed complexity of 10']]], $processor->getResponseData());
648
        $processor->getExecutionContext()->clearErrors();
649
650
        // don't let complexity reducer affect query errors
651
        $processor->processPayload('{ me { badfield } }');
652
        $this->assertArraySubset(['errors' => [['message' => 'Field "badfield" is not found in type "User"']]], $processor->getResponseData());
653
        $processor->getExecutionContext()->clearErrors();
654
655
        foreach (range(1, 5) as $cost_multiplier) {
656
            $visitor = new MaxComplexityQueryVisitor(1000); // arbitrarily high cost
657
            $processor->processPayload("{ me (cost: $cost_multiplier) { firstName, lastName, code, likes } }", ['cost' => $cost_multiplier], [$visitor]);
658
            $expected = 1 + 13 * (1 + $cost_multiplier);
659
            $this->assertEquals($expected, $visitor->getMemo());
660
        }
661
662
        // TODO, variables not yet supported
663
        /*$query = 'query costQuery ($cost: Int) { me (cost: $cost) { firstName, lastName, code, likes } }';
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
664
        foreach (range(1,5) as $cost_multiplier) {
665
          $visitor = new \Youshido\GraphQL\Execution\Visitor\MaxComplexityQueryVisitor(1000); // arbitrarily high cost
666
          $processor->processPayload($query, ['cost' => $cost_multiplier], [$visitor]);
667
          $expected = 1 + 13 * (1 + $cost_multiplier);
668
          $this->assertEquals($expected, $visitor->getMemo());
669
        }*/
670
    }
671
}
672