Completed
Push — master ( ea011c...446fa9 )
by Vladimir
55s queued 51s
created

EnumTypeTest::setUp()   C

Complexity

Conditions 10
Paths 1

Size

Total Lines 154
Code Lines 95

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 95
dl 0
loc 154
rs 6.2424
c 0
b 0
f 0
cc 10
nc 1
nop 0

How to fix   Long Method    Complexity   

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\Type;
6
7
use ArrayObject;
8
use GraphQL\GraphQL;
9
use GraphQL\Language\SourceLocation;
10
use GraphQL\Type\Definition\EnumType;
11
use GraphQL\Type\Definition\ObjectType;
12
use GraphQL\Type\Definition\Type;
13
use GraphQL\Type\Introspection;
14
use GraphQL\Type\Schema;
15
use PHPUnit\Framework\TestCase;
16
use function count;
17
use function is_array;
18
19
class EnumTypeTest extends TestCase
20
{
21
    /** @var Schema */
22
    private $schema;
23
24
    /** @var EnumType */
25
    private $ComplexEnum;
26
27
    /** @var mixed[] */
28
    private $Complex1;
29
30
    /** @var ArrayObject */
31
    private $Complex2;
32
33
    public function setUp()
34
    {
35
        $ColorType = new EnumType([
36
            'name'   => 'Color',
37
            'values' => [
38
                'RED'   => ['value' => 0],
39
                'GREEN' => ['value' => 1],
40
                'BLUE'  => ['value' => 2],
41
            ],
42
        ]);
43
44
        $simpleEnum = new EnumType([
45
            'name'   => 'SimpleEnum',
46
            'values' => [
47
                'ONE',
48
                'TWO',
49
                'THREE',
50
            ],
51
        ]);
52
53
        $Complex1 = [
54
            'someRandomFunction' => static function () {
55
            },
56
        ];
57
        $Complex2 = new ArrayObject(['someRandomValue' => 123]);
58
59
        $ComplexEnum = new EnumType([
60
            'name'   => 'Complex',
61
            'values' => [
62
                'ONE' => ['value' => $Complex1],
63
                'TWO' => ['value' => $Complex2],
64
            ],
65
        ]);
66
67
        $QueryType = new ObjectType([
68
            'name'   => 'Query',
69
            'fields' => [
70
                'colorEnum'   => [
71
                    'type'    => $ColorType,
72
                    'args'    => [
73
                        'fromEnum'   => ['type' => $ColorType],
74
                        'fromInt'    => ['type' => Type::int()],
75
                        'fromString' => ['type' => Type::string()],
76
                    ],
77
                    'resolve' => static function ($rootValue, $args) {
78
                        if (isset($args['fromInt'])) {
79
                            return $args['fromInt'];
80
                        }
81
                        if (isset($args['fromString'])) {
82
                            return $args['fromString'];
83
                        }
84
                        if (isset($args['fromEnum'])) {
85
                            return $args['fromEnum'];
86
                        }
87
                    },
88
                ],
89
                'simpleEnum'  => [
90
                    'type'    => $simpleEnum,
91
                    'args'    => [
92
                        'fromName'  => ['type' => Type::string()],
93
                        'fromValue' => ['type' => Type::string()],
94
                    ],
95
                    'resolve' => static function ($rootValue, $args) {
96
                        if (isset($args['fromName'])) {
97
                            return $args['fromName'];
98
                        }
99
                        if (isset($args['fromValue'])) {
100
                            return $args['fromValue'];
101
                        }
102
                    },
103
                ],
104
                'colorInt'    => [
105
                    'type'    => Type::int(),
106
                    'args'    => [
107
                        'fromEnum' => ['type' => $ColorType],
108
                        'fromInt'  => ['type' => Type::int()],
109
                    ],
110
                    'resolve' => static function ($rootValue, $args) {
111
                        if (isset($args['fromInt'])) {
112
                            return $args['fromInt'];
113
                        }
114
                        if (isset($args['fromEnum'])) {
115
                            return $args['fromEnum'];
116
                        }
117
                    },
118
                ],
119
                'complexEnum' => [
120
                    'type'    => $ComplexEnum,
121
                    'args'    => [
122
                        'fromEnum'         => [
123
                            'type'         => $ComplexEnum,
124
                            // Note: defaultValue is provided an *internal* representation for
125
                            // Enums, rather than the string name.
126
                            'defaultValue' => $Complex1,
127
                        ],
128
                        'provideGoodValue' => [
129
                            'type' => Type::boolean(),
130
                        ],
131
                        'provideBadValue'  => [
132
                            'type' => Type::boolean(),
133
                        ],
134
                    ],
135
                    'resolve' => static function ($rootValue, $args) use ($Complex2) {
136
                        if (! empty($args['provideGoodValue'])) {
137
                            // Note: this is one of the references of the internal values which
138
                            // ComplexEnum allows.
139
                            return $Complex2;
140
                        }
141
                        if (! empty($args['provideBadValue'])) {
142
                            // Note: similar shape, but not the same *reference*
143
                            // as Complex2 above. Enum internal values require === equality.
144
                            return new ArrayObject(['someRandomValue' => 123]);
145
                        }
146
147
                        return $args['fromEnum'];
148
                    },
149
                ],
150
            ],
151
        ]);
152
153
        $MutationType = new ObjectType([
154
            'name'   => 'Mutation',
155
            'fields' => [
156
                'favoriteEnum' => [
157
                    'type'    => $ColorType,
158
                    'args'    => ['color' => ['type' => $ColorType]],
159
                    'resolve' => static function ($rootValue, $args) {
160
                        return $args['color'] ?? null;
161
                    },
162
                ],
163
            ],
164
        ]);
165
166
        $SubscriptionType = new ObjectType([
167
            'name'   => 'Subscription',
168
            'fields' => [
169
                'subscribeToEnum' => [
170
                    'type'    => $ColorType,
171
                    'args'    => ['color' => ['type' => $ColorType]],
172
                    'resolve' => static function ($rootValue, $args) {
173
                        return $args['color'] ?? null;
174
                    },
175
                ],
176
            ],
177
        ]);
178
179
        $this->Complex1    = $Complex1;
180
        $this->Complex2    = $Complex2;
181
        $this->ComplexEnum = $ComplexEnum;
182
183
        $this->schema = new Schema([
184
            'query'        => $QueryType,
185
            'mutation'     => $MutationType,
186
            'subscription' => $SubscriptionType,
187
        ]);
188
    }
189
190
    // Describe: Type System: Enum Values
191
192
    /**
193
     * @see it('accepts enum literals as input')
194
     */
195
    public function testAcceptsEnumLiteralsAsInput() : void
196
    {
197
        self::assertEquals(
198
            ['data' => ['colorInt' => 1]],
199
            GraphQL::executeQuery($this->schema, '{ colorInt(fromEnum: GREEN) }')->toArray()
200
        );
201
    }
202
203
    /**
204
     * @see it('enum may be output type')
205
     */
206
    public function testEnumMayBeOutputType() : void
207
    {
208
        self::assertEquals(
209
            ['data' => ['colorEnum' => 'GREEN']],
210
            GraphQL::executeQuery($this->schema, '{ colorEnum(fromInt: 1) }')->toArray()
211
        );
212
    }
213
214
    /**
215
     * @see it('enum may be both input and output type')
216
     */
217
    public function testEnumMayBeBothInputAndOutputType() : void
218
    {
219
        self::assertEquals(
220
            ['data' => ['colorEnum' => 'GREEN']],
221
            GraphQL::executeQuery($this->schema, '{ colorEnum(fromEnum: GREEN) }')->toArray()
222
        );
223
    }
224
225
    /**
226
     * @see it('does not accept string literals')
227
     */
228
    public function testDoesNotAcceptStringLiterals() : void
229
    {
230
        $this->expectFailure(
231
            '{ colorEnum(fromEnum: "GREEN") }',
232
            null,
233
            [
234
                'message'   => 'Field "colorEnum" argument "fromEnum" requires type Color, found "GREEN"; Did you mean the enum value GREEN?',
235
                'locations' => [new SourceLocation(1, 23)],
236
            ]
237
        );
238
    }
239
240
    private function expectFailure($query, $vars, $err)
241
    {
242
        $result = GraphQL::executeQuery($this->schema, $query, null, null, $vars);
243
        self::assertEquals(1, count($result->errors));
244
245
        if (is_array($err)) {
246
            self::assertEquals(
247
                $err['message'],
248
                $result->errors[0]->getMessage()
249
            );
250
            self::assertEquals(
251
                $err['locations'],
252
                $result->errors[0]->getLocations()
253
            );
254
        } else {
255
            self::assertEquals(
256
                $err,
257
                $result->errors[0]->getMessage()
258
            );
259
        }
260
    }
261
262
    /**
263
     * @see it('does not accept valuesNotInTheEnum')
264
     */
265
    public function testDoesNotAcceptValuesNotInTheEnum() : void
266
    {
267
        $this->expectFailure(
268
            '{ colorEnum(fromEnum: GREENISH) }',
269
            null,
270
            [
271
                'message'   => 'Field "colorEnum" argument "fromEnum" requires type Color, found GREENISH; Did you mean the enum value GREEN?',
272
                'locations' => [new SourceLocation(1, 23)],
273
            ]
274
        );
275
    }
276
277
    /**
278
     * @see it('does not accept values with incorrect casing')
279
     */
280
    public function testDoesNotAcceptValuesWithIncorrectCasing() : void
281
    {
282
        $this->expectFailure(
283
            '{ colorEnum(fromEnum: green) }',
284
            null,
285
            [
286
                'message'   => 'Field "colorEnum" argument "fromEnum" requires type Color, found green; Did you mean the enum value GREEN?',
287
                'locations' => [new SourceLocation(1, 23)],
288
            ]
289
        );
290
    }
291
292
    /**
293
     * @see it('does not accept incorrect internal value')
294
     */
295
    public function testDoesNotAcceptIncorrectInternalValue() : void
296
    {
297
        $this->expectFailure(
298
            '{ colorEnum(fromString: "GREEN") }',
299
            null,
300
            [
301
                'message'   => 'Expected a value of type "Color" but received: GREEN',
302
                'locations' => [new SourceLocation(1, 3)],
303
                'path'      => ['colorEnum'],
304
            ]
305
        );
306
    }
307
308
    /**
309
     * @see it('does not accept internal value in place of enum literal')
310
     */
311
    public function testDoesNotAcceptInternalValueInPlaceOfEnumLiteral() : void
312
    {
313
        $this->expectFailure(
314
            '{ colorEnum(fromEnum: 1) }',
315
            null,
316
            'Field "colorEnum" argument "fromEnum" requires type Color, found 1.'
317
        );
318
    }
319
320
    /**
321
     * @see it('does not accept enum literal in place of int')
322
     */
323
    public function testDoesNotAcceptEnumLiteralInPlaceOfInt() : void
324
    {
325
        $this->expectFailure(
326
            '{ colorEnum(fromInt: GREEN) }',
327
            null,
328
            'Field "colorEnum" argument "fromInt" requires type Int, found GREEN.'
329
        );
330
    }
331
332
    /**
333
     * @see it('accepts JSON string as enum variable')
334
     */
335
    public function testAcceptsJSONStringAsEnumVariable() : void
336
    {
337
        self::assertEquals(
338
            ['data' => ['colorEnum' => 'BLUE']],
339
            GraphQL::executeQuery(
340
                $this->schema,
341
                'query test($color: Color!) { colorEnum(fromEnum: $color) }',
342
                null,
343
                null,
344
                ['color' => 'BLUE']
345
            )->toArray()
346
        );
347
    }
348
349
    /**
350
     * @see it('accepts enum literals as input arguments to mutations')
351
     */
352
    public function testAcceptsEnumLiteralsAsInputArgumentsToMutations() : void
353
    {
354
        self::assertEquals(
355
            ['data' => ['favoriteEnum' => 'GREEN']],
356
            GraphQL::executeQuery(
357
                $this->schema,
358
                'mutation x($color: Color!) { favoriteEnum(color: $color) }',
359
                null,
360
                null,
361
                ['color' => 'GREEN']
362
            )->toArray()
363
        );
364
    }
365
366
    /**
367
     * @see it('accepts enum literals as input arguments to subscriptions')
368
     *
369
     * @todo
370
     */
371
    public function testAcceptsEnumLiteralsAsInputArgumentsToSubscriptions() : void
372
    {
373
        self::assertEquals(
374
            ['data' => ['subscribeToEnum' => 'GREEN']],
375
            GraphQL::executeQuery(
376
                $this->schema,
377
                'subscription x($color: Color!) { subscribeToEnum(color: $color) }',
378
                null,
379
                null,
380
                ['color' => 'GREEN']
381
            )->toArray()
382
        );
383
    }
384
385
    /**
386
     * @see it('does not accept internal value as enum variable')
387
     */
388
    public function testDoesNotAcceptInternalValueAsEnumVariable() : void
389
    {
390
        $this->expectFailure(
391
            'query test($color: Color!) { colorEnum(fromEnum: $color) }',
392
            ['color' => 2],
393
            'Variable "$color" got invalid value 2; Expected type Color.'
394
        );
395
    }
396
397
    /**
398
     * @see it('does not accept string variables as enum input')
399
     */
400
    public function testDoesNotAcceptStringVariablesAsEnumInput() : void
401
    {
402
        $this->expectFailure(
403
            'query test($color: String!) { colorEnum(fromEnum: $color) }',
404
            ['color' => 'BLUE'],
405
            'Variable "$color" of type "String!" used in position expecting type "Color".'
406
        );
407
    }
408
409
    /**
410
     * @see it('does not accept internal value variable as enum input')
411
     */
412
    public function testDoesNotAcceptInternalValueVariableSsEnumInput() : void
413
    {
414
        $this->expectFailure(
415
            'query test($color: Int!) { colorEnum(fromEnum: $color) }',
416
            ['color' => 2],
417
            'Variable "$color" of type "Int!" used in position expecting type "Color".'
418
        );
419
    }
420
421
    /**
422
     * @see it('enum value may have an internal value of 0')
423
     */
424
    public function testEnumValueMayHaveAnInternalValueOf0() : void
425
    {
426
        self::assertEquals(
427
            ['data' => ['colorEnum' => 'RED', 'colorInt' => 0]],
428
            GraphQL::executeQuery(
429
                $this->schema,
430
                '{
431
                colorEnum(fromEnum: RED)
432
                colorInt(fromEnum: RED)
433
            }'
434
            )->toArray()
435
        );
436
    }
437
438
    /**
439
     * @see it('enum inputs may be nullable')
440
     */
441
    public function testEnumInputsMayBeNullable() : void
442
    {
443
        self::assertEquals(
444
            ['data' => ['colorEnum' => null, 'colorInt' => null]],
445
            GraphQL::executeQuery(
446
                $this->schema,
447
                '{
448
                colorEnum
449
                colorInt
450
            }'
451
            )->toArray()
452
        );
453
    }
454
455
    /**
456
     * @see it('presents a getValues() API for complex enums')
457
     */
458
    public function testPresentsGetValuesAPIForComplexEnums() : void
459
    {
460
        $ComplexEnum = $this->ComplexEnum;
461
        $values      = $ComplexEnum->getValues();
462
463
        self::assertEquals(2, count($values));
464
        self::assertEquals('ONE', $values[0]->name);
465
        self::assertEquals($this->Complex1, $values[0]->value);
466
        self::assertEquals('TWO', $values[1]->name);
467
        self::assertEquals($this->Complex2, $values[1]->value);
468
    }
469
470
    /**
471
     * @see it('presents a getValue() API for complex enums')
472
     */
473
    public function testPresentsGetValueAPIForComplexEnums() : void
474
    {
475
        $oneValue = $this->ComplexEnum->getValue('ONE');
476
        self::assertEquals('ONE', $oneValue->name);
477
        self::assertEquals($this->Complex1, $oneValue->value);
478
479
        $badUsage = $this->ComplexEnum->getValue($this->Complex1);
480
        self::assertEquals(null, $badUsage);
481
    }
482
483
    /**
484
     * @see it('may be internally represented with complex values')
485
     */
486
    public function testMayBeInternallyRepresentedWithComplexValues() : void
487
    {
488
        $result = GraphQL::executeQuery(
489
            $this->schema,
490
            '{
491
        first: complexEnum
492
        second: complexEnum(fromEnum: TWO)
493
        good: complexEnum(provideGoodValue: true)
494
        bad: complexEnum(provideBadValue: true)
495
        }'
496
        )->toArray(true);
497
498
        $expected = [
499
            'data'   => [
500
                'first'  => 'ONE',
501
                'second' => 'TWO',
502
                'good'   => 'TWO',
503
                'bad'    => null,
504
            ],
505
            'errors' => [[
506
                'debugMessage' =>
507
                    'Expected a value of type "Complex" but received: instance of ArrayObject',
508
                'locations'    => [['line' => 5, 'column' => 9]],
509
            ],
510
            ],
511
        ];
512
513
        self::assertArraySubset($expected, $result);
514
    }
515
516
    /**
517
     * @see it('can be introspected without error')
518
     */
519
    public function testCanBeIntrospectedWithoutError() : void
520
    {
521
        $result = GraphQL::executeQuery($this->schema, Introspection::getIntrospectionQuery())->toArray();
522
        self::assertArrayNotHasKey('errors', $result);
523
    }
524
525
    public function testAllowsSimpleArrayAsValues() : void
526
    {
527
        $q = '{
528
            first: simpleEnum(fromName: "ONE")
529
            second: simpleEnum(fromValue: "TWO")
530
            third: simpleEnum(fromValue: "WRONG")
531
        }';
532
533
        self::assertArraySubset(
534
            [
535
                'data'   => ['first' => 'ONE', 'second' => 'TWO', 'third' => null],
536
                'errors' => [[
537
                    'debugMessage' => 'Expected a value of type "SimpleEnum" but received: WRONG',
538
                    'locations'    => [['line' => 4, 'column' => 13]],
539
                ],
540
                ],
541
            ],
542
            GraphQL::executeQuery($this->schema, $q)->toArray(true)
543
        );
544
    }
545
}
546