Passed
Push — master ( a27dd3...975c9f )
by Vladimir
11:24
created

testCoercingAnArrayToGraphQLIDProducesAnError()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 11
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Tests\Utils;
6
7
use GraphQL\Type\Definition\EnumType;
8
use GraphQL\Type\Definition\IDType;
9
use GraphQL\Type\Definition\InputObjectType;
10
use GraphQL\Type\Definition\StringType;
11
use GraphQL\Type\Definition\Type;
12
use GraphQL\Utils\Utils;
13
use GraphQL\Utils\Value;
14
use PHPUnit\Framework\TestCase;
15
use function acos;
16
use function log;
17
use function pow;
18
use function sprintf;
19
20
class CoerceValueTest extends TestCase
21
{
22
    /** @var EnumType */
23
    private $testEnum;
24
25
    /** @var InputObjectType */
26
    private $testInputObject;
27
28
    public function setUp()
29
    {
30
        $this->testEnum = new EnumType([
31
            'name'   => 'TestEnum',
32
            'values' => [
33
                'FOO' => 'InternalFoo',
34
                'BAR' => 123456789,
35
            ],
36
        ]);
37
38
        $this->testInputObject = new InputObjectType([
39
            'name'   => 'TestInputObject',
40
            'fields' => [
41
                'foo' => Type::nonNull(Type::int()),
42
                'bar' => Type::int(),
43
            ],
44
        ]);
45
    }
46
47
    /**
48
     * Describe: coerceValue
49
     */
50
51
    /**
52
     * Describe: for GraphQLString
53
     *
54
     * @see it('returns error for array input as string')
55
     */
56
    public function testCoercingAnArrayToGraphQLStringProducesAnError() : void
57
    {
58
        $result = Value::coerceValue([1, 2, 3], Type::string());
59
        $this->expectError(
60
            $result,
61
            'Expected type String; String cannot represent a non string value: [1,2,3]'
62
        );
63
64
        self::assertEquals(
65
            'String cannot represent a non string value: [1,2,3]',
66
            $result['errors'][0]->getPrevious()->getMessage()
67
        );
68
    }
69
70
    /**
71
     * Describe: for GraphQLID
72
     *
73
     * @see it('returns error for array input as string')
74
     */
75
    public function testCoercingAnArrayToGraphQLIDProducesAnError() : void
76
    {
77
        $result = Value::coerceValue([1, 2, 3], Type::id());
78
        $this->expectError(
79
            $result,
80
            'Expected type ID; ID cannot represent value: [1,2,3]'
81
        );
82
83
        self::assertEquals(
84
            'ID cannot represent value: [1,2,3]',
85
            $result['errors'][0]->getPrevious()->getMessage()
86
        );
87
    }
88
89
    /**
90
     * Describe: for GraphQLInt
91
     */
92
    private function expectError($result, $expected)
93
    {
94
        self::assertInternalType('array', $result);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

94
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
95
        self::assertInternalType('array', $result['errors']);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

95
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result['errors']);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
96
        self::assertCount(1, $result['errors']);
97
        self::assertEquals($expected, $result['errors'][0]->getMessage());
98
        self::assertEquals(Utils::undefined(), $result['value']);
99
    }
100
101
    /**
102
     * @see it('returns value for integer')
103
     */
104
    public function testIntReturnsNoErrorForIntInput() : void
105
    {
106
        $result = Value::coerceValue(1, Type::int());
107
        $this->expectValue($result, 1);
108
    }
109
110
    /**
111
     * @see it('returns error for numeric looking string')
112
     */
113
    public function testReturnsErrorForNumericLookingString()
114
    {
115
        $result = Value::coerceValue('1', Type::int());
116
        $this->expectError($result, 'Expected type Int; Int cannot represent non-integer value: 1');
117
    }
118
119
    private function expectValue($result, $expected)
120
    {
121
        self::assertInternalType('array', $result);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

121
        /** @scrutinizer ignore-deprecated */ self::assertInternalType('array', $result);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
122
        self::assertEquals(null, $result['errors']);
123
        self::assertNotEquals(Utils::undefined(), $result['value']);
124
        self::assertEquals($expected, $result['value']);
125
    }
126
127
    /**
128
     * @see it('returns value for negative int input')
129
     */
130
    public function testIntReturnsNoErrorForNegativeIntInput() : void
131
    {
132
        $result = Value::coerceValue(-1, Type::int());
133
        $this->expectValue($result, -1);
134
    }
135
136
    /**
137
     * @see it('returns value for exponent input')
138
     */
139
    public function testIntReturnsNoErrorForExponentInput() : void
140
    {
141
        $result = Value::coerceValue(1e3, Type::int());
142
        $this->expectValue($result, 1000);
143
    }
144
145
    /**
146
     * @see it('returns null for null value')
147
     */
148
    public function testIntReturnsASingleErrorNull() : void
149
    {
150
        $result = Value::coerceValue(null, Type::int());
151
        $this->expectValue($result, null);
152
    }
153
154
    /**
155
     * @see it('returns a single error for empty string as value')
156
     */
157
    public function testIntReturnsASingleErrorForEmptyValue() : void
158
    {
159
        $result = Value::coerceValue('', Type::int());
160
        $this->expectError(
161
            $result,
162
            'Expected type Int; Int cannot represent non-integer value: (empty string)'
163
        );
164
    }
165
166
    /**
167
     * @see it('returns a single error for 2^32 input as int')
168
     */
169
    public function testReturnsASingleErrorFor2x32InputAsInt()
170
    {
171
        $result = Value::coerceValue(pow(2, 32), Type::int());
172
        $this->expectError(
173
            $result,
174
            'Expected type Int; Int cannot represent non 32-bit signed integer value: 4294967296'
175
        );
176
    }
177
178
    /**
179
     * @see it('returns error for float input as int')
180
     */
181
    public function testIntReturnsErrorForFloatInputAsInt() : void
182
    {
183
        $result = Value::coerceValue(1.5, Type::int());
184
        $this->expectError(
185
            $result,
186
            'Expected type Int; Int cannot represent non-integer value: 1.5'
187
        );
188
    }
189
190
    /**
191
     * @see it('returns a single error for Infinity input as int')
192
     */
193
    public function testReturnsASingleErrorForInfinityInputAsInt()
194
    {
195
        $inf    = log(0);
196
        $result = Value::coerceValue($inf, Type::int());
197
        $this->expectError(
198
            $result,
199
            'Expected type Int; Int cannot represent non 32-bit signed integer value: -INF'
200
        );
201
    }
202
203
    public function testReturnsASingleErrorForNaNInputAsInt()
204
    {
205
        $nan    = acos(8);
206
        $result = Value::coerceValue($nan, Type::int());
207
        $this->expectError(
208
            $result,
209
            'Expected type Int; Int cannot represent non-integer value: NAN'
210
        );
211
    }
212
213
    /**
214
     * @see it('returns a single error for string input')
215
     */
216
    public function testIntReturnsASingleErrorForCharInput() : void
217
    {
218
        $result = Value::coerceValue('a', Type::int());
219
        $this->expectError(
220
            $result,
221
            'Expected type Int; Int cannot represent non-integer value: a'
222
        );
223
    }
224
225
    /**
226
     * @see it('returns a single error for multi char input')
227
     */
228
    public function testIntReturnsASingleErrorForMultiCharInput() : void
229
    {
230
        $result = Value::coerceValue('meow', Type::int());
231
        $this->expectError(
232
            $result,
233
            'Expected type Int; Int cannot represent non-integer value: meow'
234
        );
235
    }
236
237
    // Describe: for GraphQLFloat
238
239
    /**
240
     * @see it('returns value for integer')
241
     */
242
    public function testFloatReturnsNoErrorForIntInput() : void
243
    {
244
        $result = Value::coerceValue(1, Type::float());
245
        $this->expectValue($result, 1);
246
    }
247
248
    /**
249
     * @see it('returns value for decimal')
250
     */
251
    public function testReturnsValueForDecimal()
252
    {
253
        $result = Value::coerceValue(1.1, Type::float());
254
        $this->expectValue($result, 1.1);
255
    }
256
257
    /**
258
     * @see it('returns value for exponent input')
259
     */
260
    public function testFloatReturnsNoErrorForExponentInput() : void
261
    {
262
        $result = Value::coerceValue(1e3, Type::float());
263
        $this->expectValue($result, 1000);
264
    }
265
266
    /**
267
     * @see it('returns error for numeric looking string')
268
     */
269
    public function testFloatReturnsErrorForNumericLookingString()
270
    {
271
        $result = Value::coerceValue('1', Type::float());
272
        $this->expectError(
273
            $result,
274
            'Expected type Float; Float cannot represent non numeric value: 1'
275
        );
276
    }
277
278
    /**
279
     * @see it('returns null for null value')
280
     */
281
    public function testFloatReturnsASingleErrorNull() : void
282
    {
283
        $result = Value::coerceValue(null, Type::float());
284
        $this->expectValue($result, null);
285
    }
286
287
    /**
288
     * @see it('returns a single error for empty string input')
289
     */
290
    public function testFloatReturnsASingleErrorForEmptyValue() : void
291
    {
292
        $result = Value::coerceValue('', Type::float());
293
        $this->expectError(
294
            $result,
295
            'Expected type Float; Float cannot represent non numeric value: (empty string)'
296
        );
297
    }
298
299
    /**
300
     * @see it('returns a single error for Infinity input')
301
     */
302
    public function testFloatReturnsASingleErrorForInfinityInput() : void
303
    {
304
        $inf    = log(0);
305
        $result = Value::coerceValue($inf, Type::float());
306
        $this->expectError(
307
            $result,
308
            'Expected type Float; Float cannot represent non numeric value: -INF'
309
        );
310
    }
311
312
    public function testFloatReturnsASingleErrorForNaNInput() : void
313
    {
314
        $nan    = acos(8);
315
        $result = Value::coerceValue($nan, Type::float());
316
        $this->expectError(
317
            $result,
318
            'Expected type Float; Float cannot represent non numeric value: NAN'
319
        );
320
    }
321
322
    // DESCRIBE: for GraphQLEnum
323
324
    /**
325
     * @see it('returns a single error for char input')
326
     */
327
    public function testFloatReturnsASingleErrorForCharInput() : void
328
    {
329
        $result = Value::coerceValue('a', Type::float());
330
        $this->expectError(
331
            $result,
332
            'Expected type Float; Float cannot represent non numeric value: a'
333
        );
334
    }
335
336
    /**
337
     * @see it('returns a single error for multi char input')
338
     */
339
    public function testFloatReturnsASingleErrorForMultiCharInput() : void
340
    {
341
        $result = Value::coerceValue('meow', Type::float());
342
        $this->expectError(
343
            $result,
344
            'Expected type Float; Float cannot represent non numeric value: meow'
345
        );
346
    }
347
348
    /**
349
     * @see it('returns no error for a known enum name')
350
     */
351
    public function testReturnsNoErrorForAKnownEnumName() : void
352
    {
353
        $fooResult = Value::coerceValue('FOO', $this->testEnum);
354
        $this->expectValue($fooResult, 'InternalFoo');
355
356
        $barResult = Value::coerceValue('BAR', $this->testEnum);
357
        $this->expectValue($barResult, 123456789);
358
    }
359
360
    // DESCRIBE: for GraphQLInputObject
361
362
    /**
363
     * @see it('results error for misspelled enum value')
364
     */
365
    public function testReturnsErrorForMisspelledEnumValue() : void
366
    {
367
        $result = Value::coerceValue('foo', $this->testEnum);
368
        $this->expectError($result, 'Expected type TestEnum; did you mean FOO?');
369
    }
370
371
    /**
372
     * @see it('results error for incorrect value type')
373
     */
374
    public function testReturnsErrorForIncorrectValueType() : void
375
    {
376
        $result1 = Value::coerceValue(123, $this->testEnum);
377
        $this->expectError($result1, 'Expected type TestEnum.');
378
379
        $result2 = Value::coerceValue(['field' => 'value'], $this->testEnum);
380
        $this->expectError($result2, 'Expected type TestEnum.');
381
    }
382
383
    /**
384
     * @see it('returns no error for a valid input')
385
     */
386
    public function testReturnsNoErrorForValidInput() : void
387
    {
388
        $result = Value::coerceValue(['foo' => 123], $this->testInputObject);
389
        $this->expectValue($result, ['foo' => 123]);
390
    }
391
392
    /**
393
     * @see it('returns no error for a non-object type')
394
     */
395
    public function testReturnsErrorForNonObjectType() : void
396
    {
397
        $result = Value::coerceValue(123, $this->testInputObject);
398
        $this->expectError($result, 'Expected type TestInputObject to be an object.');
399
    }
400
401
    public function testReturnsNoErrorForStdClassInput() : void
402
    {
403
        $result = Value::coerceValue((object) ['foo' => 123], $this->testInputObject);
404
        $this->expectValue($result, ['foo' => 123]);
405
    }
406
407
    /**
408
     * @see it('returns no error for an invalid field')
409
     */
410
    public function testReturnErrorForAnInvalidField() : void
411
    {
412
        $result = Value::coerceValue(['foo' => 'abc'], $this->testInputObject);
413
        $this->expectError(
414
            $result,
415
            'Expected type Int at value.foo; Int cannot represent non-integer value: abc'
416
        );
417
    }
418
419
    /**
420
     * @see it('returns multiple errors for multiple invalid fields')
421
     */
422
    public function testReturnsMultipleErrorsForMultipleInvalidFields() : void
423
    {
424
        $result = Value::coerceValue(['foo' => 'abc', 'bar' => 'def'], $this->testInputObject);
425
        self::assertEquals(
426
            [
427
                'Expected type Int at value.foo; Int cannot represent non-integer value: abc',
428
                'Expected type Int at value.bar; Int cannot represent non-integer value: def',
429
            ],
430
            $result['errors']
431
        );
432
    }
433
434
    /**
435
     * @see it('returns error for a missing required field')
436
     */
437
    public function testReturnsErrorForAMissingRequiredField() : void
438
    {
439
        $result = Value::coerceValue(['bar' => 123], $this->testInputObject);
440
        $this->expectError($result, 'Field value.foo of required type Int! was not provided.');
441
    }
442
443
    /**
444
     * @see it('returns error for an unknown field')
445
     */
446
    public function testReturnsErrorForAnUnknownField() : void
447
    {
448
        $result = Value::coerceValue(['foo' => 123, 'unknownField' => 123], $this->testInputObject);
449
        $this->expectError($result, 'Field "unknownField" is not defined by type TestInputObject.');
450
    }
451
452
    /**
453
     * @see it('returns error for a misspelled field')
454
     */
455
    public function testReturnsErrorForAMisspelledField() : void
456
    {
457
        $result = Value::coerceValue(['foo' => 123, 'bart' => 123], $this->testInputObject);
458
        $this->expectError($result, 'Field "bart" is not defined by type TestInputObject; did you mean bar?');
459
    }
460
}
461