Failed Conditions
Pull Request — master (#565)
by Šimon
10:25
created

CollectorTest::provideForTestCollectFields()

Size

Total Lines 250
Code Lines 195

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 195
dl 0
loc 250
c 1
b 0
f 0
nc 4
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Tests\Experimental\Executor;
6
7
use GraphQL\Error\FormattedError;
8
use GraphQL\Experimental\Executor\Collector;
9
use GraphQL\Experimental\Executor\Runtime;
10
use GraphQL\Language\AST\DocumentNode;
11
use GraphQL\Language\AST\Node;
12
use GraphQL\Language\AST\OperationDefinitionNode;
13
use GraphQL\Language\AST\ValueNode;
14
use GraphQL\Language\Parser;
15
use GraphQL\Tests\StarWarsSchema;
16
use GraphQL\Type\Definition\InputType;
17
use GraphQL\Type\Schema;
18
use GraphQL\Utils\AST;
19
use PHPUnit\Framework\TestCase;
20
use stdClass;
21
use Throwable;
22
use function array_map;
23
use function basename;
24
use function file_exists;
25
use function file_put_contents;
26
use function json_encode;
27
use function strlen;
28
use function strncmp;
29
use const DIRECTORY_SEPARATOR;
30
use const JSON_PRETTY_PRINT;
31
use const JSON_UNESCAPED_SLASHES;
32
use const JSON_UNESCAPED_UNICODE;
33
34
class CollectorTest extends TestCase
35
{
36
    /**
37
     * @param mixed[]|null $variableValues
38
     *
39
     * @dataProvider provideForTestCollectFields
40
     */
41
    public function testCollectFields(Schema $schema, DocumentNode $documentNode, string $operationName, ?array $variableValues)
42
    {
43
        $runtime = new class($variableValues) implements Runtime
44
        {
45
            /** @var Throwable[] */
46
            public $errors = [];
47
48
            /** @var mixed[]|null */
49
            public $variableValues;
50
51
            public function __construct($variableValues)
52
            {
53
                $this->variableValues = $variableValues;
54
            }
55
56
            public function evaluate(ValueNode $valueNode, InputType $type)
57
            {
58
                return AST::valueFromAST($valueNode, $type, $this->variableValues);
59
            }
60
61
            public function addError($error)
62
            {
63
                $this->errors[] = $error;
64
            }
65
        };
66
67
        $collector = new Collector($schema, $runtime);
68
        $collector->initialize($documentNode, $operationName);
69
70
        $pipeline = [];
71
        foreach ($collector->collectFields($collector->rootType, $collector->operation->selectionSet) as $shared) {
0 ignored issues
show
Bug introduced by
It seems like $collector->rootType can also be of type null; however, parameter $runtimeType of GraphQL\Experimental\Exe...lector::collectFields() does only seem to accept GraphQL\Type\Definition\ObjectType, maybe add an additional type check? ( Ignorable by Annotation )

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

71
        foreach ($collector->collectFields(/** @scrutinizer ignore-type */ $collector->rootType, $collector->operation->selectionSet) as $shared) {
Loading history...
72
            $execution = new stdClass();
73
            if (! empty($shared->fieldNodes)) {
74
                $execution->fieldNodes = array_map(static function (Node $node) {
75
                    return $node->toArray(true);
76
                }, $shared->fieldNodes);
77
            }
78
            if (! empty($shared->fieldName)) {
79
                $execution->fieldName = $shared->fieldName;
80
            }
81
            if (! empty($shared->resultName)) {
82
                $execution->resultName = $shared->resultName;
83
            }
84
            if (! empty($shared->argumentValueMap)) {
85
                $execution->argumentValueMap = [];
86
                /** @var Node $valueNode */
87
                foreach ($shared->argumentValueMap as $argumentName => $valueNode) {
88
                    $execution->argumentValueMap[$argumentName] = $valueNode->toArray(true);
0 ignored issues
show
Bug introduced by
The method toArray() does not exist on GraphQL\Language\AST\ValueNode. Since it exists in all sub-types, consider adding an abstract or default implementation to GraphQL\Language\AST\ValueNode. ( Ignorable by Annotation )

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

88
                    /** @scrutinizer ignore-call */ 
89
                    $execution->argumentValueMap[$argumentName] = $valueNode->toArray(true);
Loading history...
89
                }
90
            }
91
92
            $pipeline[] = $execution;
93
        }
94
        if (strncmp($operationName, 'ShouldEmitError', strlen('ShouldEmitError')) === 0) {
95
            self::assertNotEmpty($runtime->errors, 'There should be errors.');
96
        } else {
97
            self::assertEmpty($runtime->errors, 'There must be no errors. Got: ' . json_encode($runtime->errors, JSON_PRETTY_PRINT));
98
99
            if (strncmp($operationName, 'ShouldNotEmit', strlen('ShouldNotEmit')) === 0) {
100
                self::assertEmpty($pipeline, 'No instructions should be emitted.');
101
            } else {
102
                self::assertNotEmpty($pipeline, 'There should be some instructions emitted.');
103
            }
104
        }
105
106
        $result = [];
107
        if (! empty($runtime->errors)) {
108
            $result['errors'] = array_map(
109
                FormattedError::prepareFormatter(null, false),
110
                $runtime->errors
111
            );
112
        }
113
        if (! empty($pipeline)) {
114
            $result['pipeline'] = $pipeline;
115
        }
116
117
        $json = json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
118
119
        $fileName = __DIR__ . DIRECTORY_SEPARATOR . basename(__FILE__, '.php') . 'Snapshots' . DIRECTORY_SEPARATOR . $operationName . '.json';
120
        if (! file_exists($fileName)) {
121
            file_put_contents($fileName, $json);
122
        }
123
124
        self::assertStringEqualsFile($fileName, $json);
125
    }
126
127
    public function provideForTestCollectFields()
128
    {
129
        $testCases = [
130
            [
131
                StarWarsSchema::build(),
132
                'query ShouldEmitFieldWithoutArguments {
133
                    human {
134
                        name                    
135
                    }
136
                }',
137
                null,
138
            ],
139
            [
140
                StarWarsSchema::build(),
141
                'query ShouldEmitFieldThatHasArguments($id: ID!) {
142
                    human(id: $id) {
143
                        name
144
                    }
145
                }',
146
                null,
147
            ],
148
            [
149
                StarWarsSchema::build(),
150
                'query ShouldEmitForInlineFragment($id: ID!) {
151
                    ...HumanById
152
                }
153
                fragment HumanById on Query {
154
                    human(id: $id) {
155
                        ... on Human {
156
                            name
157
                        }
158
                    }
159
                }',
160
                null,
161
            ],
162
            [
163
                StarWarsSchema::build(),
164
                'query ShouldEmitObjectFieldForFragmentSpread($id: ID!) {
165
                    human(id: $id) {
166
                        ...HumanName
167
                    }
168
                }
169
                fragment HumanName on Human {
170
                    name
171
                }',
172
                null,
173
            ],
174
            [
175
                StarWarsSchema::build(),
176
                'query ShouldEmitTypeName {
177
                    queryTypeName: __typename
178
                    __typename
179
                }',
180
                null,
181
            ],
182
            [
183
                StarWarsSchema::build(),
184
                'query ShouldEmitIfIncludeConditionTrue($id: ID!, $condition: Boolean!) {
185
                    droid(id: $id) @include(if: $condition) {
186
                        id
187
                    }
188
                }',
189
                ['condition' => true],
190
            ],
191
            [
192
                StarWarsSchema::build(),
193
                'query ShouldNotEmitIfIncludeConditionFalse($id: ID!, $condition: Boolean!) {
194
                    droid(id: $id) @include(if: $condition) {
195
                        id
196
                    }
197
                }',
198
                ['condition' => false],
199
            ],
200
            [
201
                StarWarsSchema::build(),
202
                'query ShouldNotEmitIfSkipConditionTrue($id: ID!, $condition: Boolean!) {
203
                    droid(id: $id) @skip(if: $condition) {
204
                        id
205
                    }
206
                }',
207
                ['condition' => true],
208
            ],
209
            [
210
                StarWarsSchema::build(),
211
                'query ShouldEmitIfSkipConditionFalse($id: ID!, $condition: Boolean!) {
212
                    droid(id: $id) @skip(if: $condition) {
213
                        id
214
                    }
215
                }',
216
                ['condition' => false],
217
            ],
218
            [
219
                StarWarsSchema::build(),
220
                'query ShouldNotEmitIncludeSkipTT($id: ID!, $includeCondition: Boolean!, $skipCondition: Boolean!) {
221
                    droid(id: $id) @include(if: $includeCondition) @skip(if: $skipCondition) {
222
                        id
223
                    }
224
                }',
225
                ['includeCondition' => true, 'skipCondition' => true],
226
            ],
227
            [
228
                StarWarsSchema::build(),
229
                'query ShouldEmitIncludeSkipTF($id: ID!, $includeCondition: Boolean!, $skipCondition: Boolean!) {
230
                    droid(id: $id) @include(if: $includeCondition) @skip(if: $skipCondition) {
231
                        id
232
                    }
233
                }',
234
                ['includeCondition' => true, 'skipCondition' => false],
235
            ],
236
            [
237
                StarWarsSchema::build(),
238
                'query ShouldNotEmitIncludeSkipFT($id: ID!, $includeCondition: Boolean!, $skipCondition: Boolean!) {
239
                    droid(id: $id) @include(if: $includeCondition) @skip(if: $skipCondition) {
240
                        id
241
                    }
242
                }',
243
                ['includeCondition' => false, 'skipCondition' => true],
244
            ],
245
            [
246
                StarWarsSchema::build(),
247
                'query ShouldNotEmitIncludeSkipFF($id: ID!, $includeCondition: Boolean!, $skipCondition: Boolean!) {
248
                    droid(id: $id) @include(if: $includeCondition) @skip(if: $skipCondition) {
249
                        id
250
                    }
251
                }',
252
                ['includeCondition' => false, 'skipCondition' => false],
253
            ],
254
            [
255
                StarWarsSchema::build(),
256
                'query ShouldNotEmitSkipAroundInlineFragment {
257
                    ... on Query @skip(if: true) {
258
                        hero(episode: 5) {
259
                            name
260
                        }
261
                    }
262
                }',
263
                null,
264
            ],
265
            [
266
                StarWarsSchema::build(),
267
                'query ShouldEmitSkipAroundInlineFragment {
268
                    ... on Query @skip(if: false) {
269
                        hero(episode: 5) {
270
                            name
271
                        }
272
                    }
273
                }',
274
                null,
275
            ],
276
            [
277
                StarWarsSchema::build(),
278
                'query ShouldEmitIncludeAroundInlineFragment {
279
                    ... on Query @include(if: true) {
280
                        hero(episode: 5) {
281
                            name
282
                        }
283
                    }
284
                }',
285
                null,
286
            ],
287
            [
288
                StarWarsSchema::build(),
289
                'query ShouldNotEmitIncludeAroundInlineFragment {
290
                    ... on Query @include(if: false) {
291
                        hero(episode: 5) {
292
                            name
293
                        }
294
                    }
295
                }',
296
                null,
297
            ],
298
            [
299
                StarWarsSchema::build(),
300
                'query ShouldNotEmitSkipFragmentSpread {
301
                    ...Hero @skip(if: true)
302
                }
303
                fragment Hero on Query {
304
                    hero(episode: 5) {
305
                        name
306
                    }
307
                }',
308
                null,
309
            ],
310
            [
311
                StarWarsSchema::build(),
312
                'query ShouldEmitSkipFragmentSpread {
313
                    ...Hero @skip(if: false)
314
                }
315
                fragment Hero on Query {
316
                    hero(episode: 5) {
317
                        name
318
                    }
319
                }',
320
                null,
321
            ],
322
            [
323
                StarWarsSchema::build(),
324
                'query ShouldEmitIncludeFragmentSpread {
325
                    ...Hero @include(if: true)
326
                }
327
                fragment Hero on Query {
328
                    hero(episode: 5) {
329
                        name
330
                    }
331
                }',
332
                null,
333
            ],
334
            [
335
                StarWarsSchema::build(),
336
                'query ShouldNotEmitIncludeFragmentSpread {
337
                    ...Hero @include(if: false)
338
                }
339
                fragment Hero on Query {
340
                    hero(episode: 5) {
341
                        name
342
                    }
343
                }',
344
                null,
345
            ],
346
            [
347
                StarWarsSchema::build(),
348
                'query ShouldEmitSingleInstrictionForSameResultName($id: ID!) {
349
                    human(id: $id) {
350
                        name
351
                        name: secretBackstory 
352
                    }
353
                }',
354
                null,
355
            ],
356
        ];
357
358
        $data = [];
359
        foreach ($testCases as [$schema, $query, $variableValues]) {
360
            $documentNode  = Parser::parse($query, ['noLocation' => true]);
361
            $operationName = null;
362
            /** @var Node $definitionNode */
363
            foreach ($documentNode->definitions as $definitionNode) {
364
                if ($definitionNode instanceof OperationDefinitionNode) {
365
                    self::assertNotNull($definitionNode->name);
366
                    $operationName = $definitionNode->name->value;
367
                    break;
368
                }
369
            }
370
371
            self::assertArrayNotHasKey($operationName, $data);
372
373
            $data[$operationName] = [$schema, $documentNode, $operationName, $variableValues];
374
        }
375
376
        return $data;
377
    }
378
}
379