Completed
Push — master ( 382658...65f525 )
by David
19s
created

ControllerQueryProviderTest.php$3 ➔ isAllowed()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
1
<?php
2
3
namespace TheCodingMachine\GraphQL\Controllers;
4
5
use Doctrine\Common\Annotations\AnnotationReader;
6
use GraphQL\Type\Definition\BooleanType;
7
use GraphQL\Type\Definition\FloatType;
8
use GraphQL\Type\Definition\IDType;
9
use GraphQL\Type\Definition\InputObjectType;
10
use GraphQL\Type\Definition\IntType;
11
use GraphQL\Type\Definition\ListOfType;
12
use GraphQL\Type\Definition\NonNull;
13
use GraphQL\Type\Definition\StringType;
14
use GraphQL\Type\Definition\ObjectType;
15
use TheCodingMachine\GraphQL\Controllers\Fixtures\TestController;
16
use TheCodingMachine\GraphQL\Controllers\Fixtures\TestObject;
17
use TheCodingMachine\GraphQL\Controllers\Fixtures\TestType;
18
use TheCodingMachine\GraphQL\Controllers\Fixtures\TestTypeId;
19
use TheCodingMachine\GraphQL\Controllers\Fixtures\TestTypeMissingAnnotation;
20
use TheCodingMachine\GraphQL\Controllers\Fixtures\TestTypeMissingField;
21
use TheCodingMachine\GraphQL\Controllers\Fixtures\TestTypeWithSourceFieldInterface;
22
use TheCodingMachine\GraphQL\Controllers\Registry\EmptyContainer;
23
use TheCodingMachine\GraphQL\Controllers\Registry\Registry;
24
use TheCodingMachine\GraphQL\Controllers\Security\AuthenticationServiceInterface;
25
use TheCodingMachine\GraphQL\Controllers\Security\AuthorizationServiceInterface;
26
use TheCodingMachine\GraphQL\Controllers\Security\VoidAuthenticationService;
27
use TheCodingMachine\GraphQL\Controllers\Security\VoidAuthorizationService;
28
use TheCodingMachine\GraphQL\Controllers\Annotations\Query;
29
use TheCodingMachine\GraphQL\Controllers\Types\DateTimeType;
30
31
class ControllerQueryProviderTest extends AbstractQueryProviderTest
32
{
33
    public function testQueryProvider()
34
    {
35
        $controller = new TestController();
36
37
        $queryProvider = new ControllerQueryProvider($controller, $this->getRegistry());
38
39
        $queries = $queryProvider->getQueries();
40
41
        $this->assertCount(5, $queries);
42
        $usersQuery = $queries[0];
43
        $this->assertSame('test', $usersQuery->name);
44
45
        $this->assertCount(8, $usersQuery->args);
46
        $this->assertSame('int', $usersQuery->args[0]->name);
47
        $this->assertInstanceOf(NonNull::class, $usersQuery->args[0]->getType());
48
        $this->assertInstanceOf(IntType::class, $usersQuery->args[0]->getType()->getWrappedType());
49
        $this->assertInstanceOf(StringType::class, $usersQuery->args[7]->getType());
50
        $this->assertInstanceOf(NonNull::class, $usersQuery->args[1]->getType());
51
        $this->assertInstanceOf(ListOfType::class, $usersQuery->args[1]->getType()->getWrappedType());
52
        $this->assertInstanceOf(NonNull::class, $usersQuery->args[1]->getType()->getWrappedType()->getWrappedType());
53
        $this->assertInstanceOf(InputObjectType::class, $usersQuery->args[1]->getType()->getWrappedType()->getWrappedType()->getWrappedType());
54
        $this->assertInstanceOf(BooleanType::class, $usersQuery->args[2]->getType());
55
        $this->assertInstanceOf(FloatType::class, $usersQuery->args[3]->getType());
56
        $this->assertInstanceOf(DateTimeType::class, $usersQuery->args[4]->getType());
57
        $this->assertInstanceOf(DateTimeType::class, $usersQuery->args[5]->getType());
58
        $this->assertInstanceOf(StringType::class, $usersQuery->args[6]->getType());
59
        $this->assertSame('TestObject', $usersQuery->args[1]->getType()->getWrappedType()->getWrappedType()->getWrappedType()->name);
60
61
        $context = ['int' => 42, 'string' => 'foo', 'list' => [
62
            ['test' => 42],
63
            ['test' => 12],
64
        ],
65
            'boolean' => true,
66
            'float' => 4.2,
67
            'dateTimeImmutable' => '2017-01-01 01:01:01',
68
            'dateTime' => '2017-01-01 01:01:01'
69
        ];
70
71
        $resolve = $usersQuery->resolveFn;
72
        $result = $resolve('foo', $context);
73
74
        $this->assertInstanceOf(TestObject::class, $result);
75
        $this->assertSame('foo424212true4.22017010101010120170101010101default', $result->getTest());
76
77
        unset($context['string']); // Testing null default value
78
        $result = $resolve('foo', $context);
79
80
        $this->assertSame('424212true4.22017010101010120170101010101default', $result->getTest());
81
    }
82
83
    public function testMutations()
84
    {
85
        $controller = new TestController();
86
87
        $queryProvider = new ControllerQueryProvider($controller, $this->getRegistry());
88
89
        $mutations = $queryProvider->getMutations();
90
91
        $this->assertCount(1, $mutations);
92
        $mutation = $mutations[0];
93
        $this->assertSame('mutation', $mutation->name);
94
95
        $resolve = $mutation->resolveFn;
96
        $result = $resolve('foo', ['testObject' => ['test' => 42]]);
97
98
        $this->assertInstanceOf(TestObject::class, $result);
99
        $this->assertEquals('42', $result->getTest());
100
    }
101
102
    public function testErrors()
103
    {
104
        $controller = new class
105
        {
106
            /**
107
             * @Query
108
             * @return string
109
             */
110
            public function test($noTypeHint): string
0 ignored issues
show
Unused Code introduced by
The parameter $noTypeHint is not used and could be removed. ( Ignorable by Annotation )

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

110
            public function test(/** @scrutinizer ignore-unused */ $noTypeHint): string

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

Loading history...
111
            {
112
                return 'foo';
113
            }
114
        };
115
116
        $queryProvider = new ControllerQueryProvider($controller, $this->getRegistry());
117
118
        $this->expectException(MissingTypeHintException::class);
119
        $queryProvider->getQueries();
120
    }
121
122
    public function testQueryProviderWithFixedReturnType()
123
    {
124
        $controller = new TestController();
125
126
        $queryProvider = new ControllerQueryProvider($controller, $this->getRegistry());
127
128
        $queries = $queryProvider->getQueries();
129
130
        $this->assertCount(5, $queries);
131
        $fixedQuery = $queries[1];
132
133
        $this->assertInstanceOf(ObjectType::class, $fixedQuery->getType());
134
        $this->assertSame('Test', $fixedQuery->getType()->name);
135
    }
136
137
    public function testNameFromAnnotation()
138
    {
139
        $controller = new TestController();
140
141
        $queryProvider = new ControllerQueryProvider($controller, $this->getRegistry());
142
143
        $queries = $queryProvider->getQueries();
144
145
        $query = $queries[2];
146
147
        $this->assertSame('nameFromAnnotation', $query->name);
148
    }
149
150
    public function testSourceField()
151
    {
152
        $controller = new TestType($this->getRegistry());
0 ignored issues
show
Unused Code introduced by
The call to TheCodingMachine\GraphQL...TestType::__construct() has too many arguments starting with $this->getRegistry(). ( Ignorable by Annotation )

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

152
        $controller = /** @scrutinizer ignore-call */ new TestType($this->getRegistry());

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
153
154
        $queryProvider = new ControllerQueryProvider($controller, $this->getRegistry());
155
156
        $fields = $queryProvider->getFields();
157
158
        $this->assertCount(2, $fields);
159
160
        $this->assertSame('customField', $fields[0]->name);
161
        $this->assertSame('test', $fields[1]->name);
162
    }
163
164
    public function testLoggedInSourceField()
165
    {
166
        $registry = new Registry(new EmptyContainer(),
167
            new VoidAuthorizationService(),
168
            new class implements AuthenticationServiceInterface {
169
                public function isLogged(): bool
170
                {
171
                    return true;
172
                }
173
            },
174
            new AnnotationReader(),
175
            $this->getTypeMapper(),
176
            $this->getHydrator());
177
178
        $queryProvider = new ControllerQueryProvider(new TestType($this->getRegistry()), $registry);
0 ignored issues
show
Unused Code introduced by
The call to TheCodingMachine\GraphQL...TestType::__construct() has too many arguments starting with $this->getRegistry(). ( Ignorable by Annotation )

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

178
        $queryProvider = new ControllerQueryProvider(/** @scrutinizer ignore-call */ new TestType($this->getRegistry()), $registry);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
179
        $fields = $queryProvider->getFields();
180
        $this->assertCount(3, $fields);
181
182
        $this->assertSame('testBool', $fields[2]->name);
183
184
    }
185
186
    public function testRightInSourceField()
187
    {
188
        $registry = new Registry(new EmptyContainer(),
189
            new class implements AuthorizationServiceInterface {
190
                public function isAllowed(string $right): bool
191
                {
192
                    return true;
193
                }
194
            },
195
            new VoidAuthenticationService(),
196
            new AnnotationReader(),
197
            $this->getTypeMapper(),
198
            $this->getHydrator());
199
200
        $queryProvider = new ControllerQueryProvider(new TestType(), $registry);
201
        $fields = $queryProvider->getFields();
202
        $this->assertCount(3, $fields);
203
204
        $this->assertSame('testRight', $fields[2]->name);
205
206
    }
207
208
    public function testMissingTypeAnnotation()
209
    {
210
        $queryProvider = new ControllerQueryProvider(new TestTypeMissingAnnotation(), $this->getRegistry());
211
212
        $this->expectException(MissingAnnotationException::class);
213
        $queryProvider->getFields();
214
    }
215
216
    public function testSourceFieldDoesNotExists()
217
    {
218
        $queryProvider = new ControllerQueryProvider(new TestTypeMissingField(), $this->getRegistry());
219
220
        $this->expectException(FieldNotFoundException::class);
221
        $this->expectExceptionMessage("There is an issue with a @SourceField annotation in class \"TheCodingMachine\GraphQL\Controllers\Fixtures\TestTypeMissingField\": Could not find a getter or a isser for field \"notExists\". Looked for: \"TheCodingMachine\GraphQL\Controllers\Fixtures\TestObject::getNotExists()\", \"TheCodingMachine\GraphQL\Controllers\Fixtures\TestObject::isNotExists()");
222
        $queryProvider->getFields();
223
    }
224
225
    public function testSourceFieldIsId()
226
    {
227
        $queryProvider = new ControllerQueryProvider(new TestTypeId(), $this->getRegistry());
228
        $fields = $queryProvider->getFields();
229
        $this->assertCount(1, $fields);
230
231
        $this->assertSame('test', $fields[0]->name);
232
        $this->assertInstanceOf(NonNull::class, $fields[0]->getType());
233
        $this->assertInstanceOf(IDType::class, $fields[0]->getType()->getWrappedType());
234
    }
235
236
    public function testFromSourceFieldsInterface()
237
    {
238
        $registry = new Registry(new EmptyContainer(),
239
            new class implements AuthorizationServiceInterface {
240
                public function isAllowed(string $right): bool
241
                {
242
                    return true;
243
                }
244
            },
245
            new VoidAuthenticationService(),
246
            new AnnotationReader(),
247
            $this->getTypeMapper(),
248
            $this->getHydrator());
249
250
        $queryProvider = new ControllerQueryProvider(new TestTypeWithSourceFieldInterface(), $registry);
251
        $fields = $queryProvider->getFields();
252
        $this->assertCount(1, $fields);
253
254
        $this->assertSame('test', $fields[0]->name);
255
256
    }
257
258
    public function testQueryProviderWithIterableClass()
259
    {
260
        $controller = new TestController();
261
262
        $queryProvider = new ControllerQueryProvider($controller, $this->getRegistry());
263
264
        $queries = $queryProvider->getQueries();
265
266
        $this->assertCount(5, $queries);
267
        $iterableQuery = $queries[3];
268
269
        $this->assertInstanceOf(NonNull::class, $iterableQuery->getType());
270
        $this->assertInstanceOf(ListOfType::class, $iterableQuery->getType()->getWrappedType());
271
        $this->assertInstanceOf(NonNull::class, $iterableQuery->getType()->getWrappedType()->getWrappedType());
272
        $this->assertInstanceOf(ObjectType::class, $iterableQuery->getType()->getWrappedType()->getWrappedType()->getWrappedType());
273
        $this->assertSame('TestObject', $iterableQuery->getType()->getWrappedType()->getWrappedType()->getWrappedType()->name);
274
    }
275
276
    public function testQueryProviderWithIterable()
277
    {
278
        $controller = new TestController();
279
280
        $queryProvider = new ControllerQueryProvider($controller, $this->getRegistry());
281
282
        $queries = $queryProvider->getQueries();
283
284
        $this->assertCount(5, $queries);
285
        $iterableQuery = $queries[4];
286
287
        $this->assertInstanceOf(NonNull::class, $iterableQuery->getType());
288
        $this->assertInstanceOf(ListOfType::class, $iterableQuery->getType()->getWrappedType());
289
        $this->assertInstanceOf(NonNull::class, $iterableQuery->getType()->getWrappedType()->getWrappedType());
290
        $this->assertInstanceOf(ObjectType::class, $iterableQuery->getType()->getWrappedType()->getWrappedType()->getWrappedType());
291
        $this->assertSame('TestObject', $iterableQuery->getType()->getWrappedType()->getWrappedType()->getWrappedType()->name);
292
    }
293
}
294