Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace core\router;
18
 
19
use core\param;
20
use core\router\response\empty_response;
21
use core\router\route;
22
use core\router\schema\parameters\header_object;
23
use core\router\schema\parameters\path_parameter;
24
use core\router\schema\parameters\query_parameter;
25
use core\router\schema\request_body;
26
use core\router\schema\response\response;
27
use core\tests\router\route_testcase;
28
 
29
/**
30
 * Tests for user preference API handler.
31
 *
32
 * @package   core
33
 * @copyright Andrew Lyons <andrew@nicols.co.uk>
34
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35
 * @covers    \core\router\route
36
 */
37
final class route_test extends route_testcase {
38
    /**
39
     * Test that the Attribute is configured correctly.
40
     */
41
    public function test_attributes(): void {
42
        $route = new \ReflectionClass(route::class);
43
        $this->assertNotEmpty($route->getAttributes());
44
 
45
        $this->assertNotEmpty($route->getAttributes(\Attribute::class));
46
        $attributes = $route->getAttributes(\Attribute::class);
47
        $this->assertCount(1, $attributes);
48
        $attribute = reset($attributes);
49
        $flags = $attribute->getArguments()[0];
50
 
51
        // This can only be set on class, and method.
52
        $this->assertEquals(\Attribute::TARGET_CLASS, $flags & \Attribute::TARGET_CLASS);
53
        $this->assertEquals(\Attribute::TARGET_METHOD, $flags & \Attribute::TARGET_METHOD);
54
 
55
        // Only one per method or class allowed.
56
        $this->assertEquals(0, \Attribute::IS_REPEATABLE & $flags);
57
 
58
        // Yes, this is a poor test, but if someone wants to extend this attribute in future,
59
        // they need to write appropriate tests for it.
60
        $this->assertEquals(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD, $flags);
61
    }
62
 
63
    /**
64
     * Test that path setting and getting works as expected.
65
     */
66
    public function test_get_path(): void {
67
        $route = new route(
68
            path: '/example',
69
        );
70
 
71
        $this->assertEquals('/example', $route->get_path());
72
 
73
        // And with a parent.
74
        $child = new route(
75
            path: '/child/path',
76
        );
77
        $child->set_parent($route);
78
        $this->assertEquals('/example/child/path', $child->get_path());
79
 
80
        // But the parent is not changed in any way.
81
        $this->assertEquals('/example', $route->get_path());
82
    }
83
 
84
 
85
    /**
86
     * Test the default method.
87
     */
88
    public function test_get_methods(): void {
89
        // No method specified.
90
        $route = new route();
91
        $this->assertNull($route->get_methods());
92
 
93
        // With a method.
94
        $route = new route(
95
            method: 'POST',
96
        );
97
        $this->assertEquals(['POST'], $route->get_methods());
98
 
99
        // An array of methods.
100
        $route = new route(
101
            method: ['POST', 'PUT'],
102
        );
103
        $this->assertEquals(['POST', 'PUT'], $route->get_methods());
104
 
105
        // A route which inherits its method from its parent.
106
        $child = new route();
107
        $child->set_parent($route);
108
        $this->assertEquals(['POST', 'PUT'], $child->get_methods());
109
 
110
        // A child route will merge its own methods with its parents.
111
        $child = new route(
112
            method: 'GET',
113
        );
114
        $child->set_parent($route);
115
        $this->assertEquals(['GET', 'POST', 'PUT'], $child->get_methods());
116
 
117
        // A child route which shares some will not duplicate.
118
        $child = new route(
119
            method: ['GET', 'PUT'],
120
        );
121
        $child->set_parent($route);
122
        $this->assertEquals(['GET', 'POST', 'PUT'], $child->get_methods());
123
    }
124
 
125
    /**
126
     * Ensure that pathtypes and queryparams accept query parameters correctly.
127
     */
128
    public function test_params_are_params(): void {
129
        $route = new route(
130
            pathtypes: [
131
                new path_parameter(
132
                    name: 'example',
133
                    type: param::RAW,
134
                ),
135
                new path_parameter(
136
                    name: 'another',
137
                    type: param::INT,
138
                ),
139
            ],
140
            queryparams: [
141
                new query_parameter(
142
                    name: 'example',
143
                    type: param::RAW,
144
                ),
145
                new query_parameter(
146
                    name: 'another',
147
                    type: param::INT,
148
                ),
149
            ],
150
        );
151
        $this->assertInstanceOf(route::class, $route);
152
    }
153
 
154
    /**
155
     * Ensure that pathtypes and queryparams do not accept the wrong type of parameter.
156
     *
157
     * @dataProvider invalid_constructor_param_types
158
     * @param array $args
159
     */
160
    public function test_params_not_params(array $args): void {
161
        $this->expectException(\coding_exception::class);
162
        new route(...$args);
163
    }
164
 
165
    /**
166
     * Data provider for test_params_not_params.
167
     *
168
     * @return array
169
     */
170
    public static function invalid_constructor_param_types(): array {
171
        return [
172
            'not a param at all in queryparams' => [
173
                'args' => [
174
                    'queryparams' => [
175
                        new query_parameter(
176
                            name: 'another',
177
                            type: param::INT,
178
                        ),
179
                        new \stdClass(),
180
                    ],
181
                ],
182
            ],
183
            'not a param at all in pathtypes' => [
184
                'args' => [
185
                    'pathtypes' => [
186
                        new path_parameter(
187
                            name: 'another',
188
                            type: param::INT,
189
                        ),
190
                        new \stdClass(),
191
                    ],
192
                ],
193
            ],
194
            'not a param at all in headerparams' => [
195
                'args' => [
196
                    'headerparams' => [
197
                        new header_object(
198
                            name: 'another',
199
                            type: param::INT,
200
                        ),
201
                        new \stdClass(),
202
                    ],
203
                ],
204
            ],
205
            'path_parameter in queryparams' => [
206
                'args' => [
207
                    'queryparams' => [
208
                        new path_parameter(
209
                            name: 'example',
210
                            type: param::RAW,
211
                        ),
212
                        new query_parameter(
213
                            name: 'another',
214
                            type: param::INT,
215
                        ),
216
                    ],
217
                ],
218
            ],
219
            'query_parameter in pathtype' => [
220
                'args' => [
221
                    'pathtypes' => [
222
                        new path_parameter(
223
                            name: 'example',
224
                            type: param::RAW,
225
                        ),
226
                        new query_parameter(
227
                            name: 'another',
228
                            type: param::INT,
229
                        ),
230
                    ],
231
                ],
232
            ],
233
            'query_parameter in header' => [
234
                'args' => [
235
                    'headerparams' => [
236
                        new path_parameter(
237
                            name: 'example',
238
                            type: param::RAW,
239
                        ),
240
                        new query_parameter(
241
                            name: 'another',
242
                            type: param::INT,
243
                        ),
244
                    ],
245
                ],
246
            ],
247
        ];
248
    }
249
 
250
    public function test_get_path_parameters(): void {
251
        // No parameters at all.
252
        $route = new route();
253
        $this->assertEmpty($route->get_path_parameters());
254
 
255
        $child = new route();
256
        $child->set_parent($route);
257
        $this->assertEmpty($child->get_path_parameters());
258
 
259
        // A route with a single parameter.
260
        $route = new route(
261
            pathtypes: [
262
                new path_parameter(
263
                    name: 'example',
264
                    type: param::SAFEPATH,
265
                ),
266
            ],
267
        );
268
        $params = $route->get_path_parameters();
269
        $this->assertCount(1, $params);
270
        $this->assertArrayHasKey('example', $params);
271
        $this->assertInstanceOf(path_parameter::class, $params['example']);
272
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
273
 
274
        // A route with a multiple parameters.
275
        $route = new route(
276
            pathtypes: [
277
                new path_parameter(
278
                    name: 'example',
279
                    type: param::SAFEPATH,
280
                ),
281
                new path_parameter(
282
                    name: 'another',
283
                    type: param::INT,
284
                ),
285
            ],
286
        );
287
        $params = $route->get_path_parameters();
288
        $this->assertCount(2, $params);
289
        $this->assertArrayHasKey('example', $params);
290
        $this->assertArrayHasKey('another', $params);
291
        $this->assertInstanceOf(path_parameter::class, $params['example']);
292
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
293
        $this->assertInstanceOf(path_parameter::class, $params['another']);
294
        $this->assertEquals(param::INT, $params['another']->get_type());
295
 
296
        // A child will also inhereit any params from the parent.
297
        $child = new route(
298
            pathtypes: [
299
                new path_parameter(
300
                    name: 'childparam',
301
                    type: param::COMPONENT,
302
                ),
303
            ],
304
        );
305
        $child->set_parent($route);
306
        $params = $child->get_path_parameters();
307
        $this->assertCount(3, $params);
308
        $this->assertArrayHasKey('example', $params);
309
        $this->assertArrayHasKey('another', $params);
310
        $this->assertArrayHasKey('childparam', $params);
311
        $this->assertInstanceOf(path_parameter::class, $params['example']);
312
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
313
        $this->assertInstanceOf(path_parameter::class, $params['another']);
314
        $this->assertEquals(param::INT, $params['another']->get_type());
315
        $this->assertInstanceOf(path_parameter::class, $params['childparam']);
316
        $this->assertEquals(param::COMPONENT, $params['childparam']->get_type());
317
    }
318
 
319
    public function test_get_header_parameters(): void {
320
        // No parameters at all.
321
        $route = new route();
322
        $this->assertEmpty($route->get_header_parameters());
323
 
324
        $child = new route();
325
        $child->set_parent($route);
326
        $this->assertEmpty($child->get_header_parameters());
327
 
328
        // A route with a single parameter.
329
        $route = new route(
330
            headerparams: [
331
                new header_object(
332
                    name: 'example',
333
                    type: param::SAFEPATH,
334
                ),
335
            ],
336
        );
337
        $params = $route->get_header_parameters();
338
        $this->assertCount(1, $params);
339
        $this->assertArrayHasKey('example', $params);
340
        $this->assertInstanceOf(header_object::class, $params['example']);
341
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
342
 
343
        // A route with a multiple parameters.
344
        $route = new route(
345
            headerparams: [
346
                new header_object(
347
                    name: 'example',
348
                    type: param::SAFEPATH,
349
                ),
350
                new header_object(
351
                    name: 'another',
352
                    type: param::INT,
353
                ),
354
            ],
355
        );
356
        $params = $route->get_header_parameters();
357
        $this->assertCount(2, $params);
358
        $this->assertArrayHasKey('example', $params);
359
        $this->assertArrayHasKey('another', $params);
360
        $this->assertInstanceOf(header_object::class, $params['example']);
361
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
362
        $this->assertInstanceOf(header_object::class, $params['another']);
363
        $this->assertEquals(param::INT, $params['another']->get_type());
364
 
365
        // A child will also inhereit any params from the parent.
366
        $child = new route(
367
            headerparams: [
368
                new header_object(
369
                    name: 'childparam',
370
                    type: param::COMPONENT,
371
                ),
372
            ],
373
        );
374
        $child->set_parent($route);
375
        $params = $child->get_header_parameters();
376
        $this->assertCount(3, $params);
377
        $this->assertArrayHasKey('example', $params);
378
        $this->assertArrayHasKey('another', $params);
379
        $this->assertArrayHasKey('childparam', $params);
380
        $this->assertInstanceOf(header_object::class, $params['example']);
381
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
382
        $this->assertInstanceOf(header_object::class, $params['another']);
383
        $this->assertEquals(param::INT, $params['another']->get_type());
384
        $this->assertInstanceOf(header_object::class, $params['childparam']);
385
        $this->assertEquals(param::COMPONENT, $params['childparam']->get_type());
386
    }
387
 
388
    public function test_get_query_parameters(): void {
389
        // No parameters at all.
390
        $route = new route();
391
        $this->assertEmpty($route->get_query_parameters());
392
 
393
        $child = new route();
394
        $child->set_parent($route);
395
        $this->assertEmpty($child->get_query_parameters());
396
 
397
        // A route with a single parameter.
398
        $route = new route(
399
            queryparams: [
400
                new query_parameter(
401
                    name: 'example',
402
                    type: param::SAFEPATH,
403
                ),
404
            ],
405
        );
406
        $params = $route->get_query_parameters();
407
        $this->assertCount(1, $params);
408
        $this->assertArrayHasKey('example', $params);
409
        $this->assertInstanceOf(query_parameter::class, $params['example']);
410
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
411
 
412
        // A route with a multiple parameters.
413
        $route = new route(
414
            queryparams: [
415
                new query_parameter(
416
                    name: 'example',
417
                    type: param::SAFEPATH,
418
                ),
419
                new query_parameter(
420
                    name: 'another',
421
                    type: param::INT,
422
                ),
423
            ],
424
        );
425
        $params = $route->get_query_parameters();
426
        $this->assertCount(2, $params);
427
        $this->assertArrayHasKey('example', $params);
428
        $this->assertArrayHasKey('another', $params);
429
        $this->assertInstanceOf(query_parameter::class, $params['example']);
430
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
431
        $this->assertInstanceOf(query_parameter::class, $params['another']);
432
        $this->assertEquals(param::INT, $params['another']->get_type());
433
 
434
        // A child will also inhereit any params from the parent.
435
        $child = new route(
436
            queryparams: [
437
                new query_parameter(
438
                    name: 'childparam',
439
                    type: param::COMPONENT,
440
                ),
441
            ],
442
        );
443
        $child->set_parent($route);
444
        $params = $child->get_query_parameters();
445
        $this->assertCount(3, $params);
446
        $this->assertArrayHasKey('example', $params);
447
        $this->assertArrayHasKey('another', $params);
448
        $this->assertArrayHasKey('childparam', $params);
449
        $this->assertInstanceOf(query_parameter::class, $params['example']);
450
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
451
        $this->assertInstanceOf(query_parameter::class, $params['another']);
452
        $this->assertEquals(param::INT, $params['another']->get_type());
453
        $this->assertInstanceOf(query_parameter::class, $params['childparam']);
454
        $this->assertEquals(param::COMPONENT, $params['childparam']->get_type());
455
    }
456
 
457
    /**
458
     * Test that has_request_body works as expected.
459
     */
460
    public function test_has_request_body(): void {
461
        $route = new route();
462
        $this->assertFalse($route->has_request_body());
463
 
464
        $route = new route(
465
            requestbody: new request_body(),
466
        );
467
        $this->assertTrue($route->has_request_body());
468
    }
469
 
470
    public function test_get_request_body(): void {
471
        $route = new route();
472
        $this->assertNull($route->get_request_body());
473
 
474
        $body = new request_body();
475
        $route = new route(
476
            requestbody: $body,
477
        );
478
        $this->assertEquals($body, $route->get_request_body());
479
 
480
    }
481
 
482
    /**
483
     * Ensure that has_any_validatable_parameter checks the param types.
484
     */
485
    public function test_has_any_validatable_parameter(): void {
486
        // No validatable params.
487
        $route = new route();
488
        $this->assertFalse($route->has_any_validatable_parameter());
489
 
490
        // A pathtype is a validatable param.
491
        $route = new route(
492
            pathtypes: [
493
                new path_parameter(
494
                    name: 'example',
495
                    type: param::INT,
496
                ),
497
            ],
498
        );
499
        $this->assertTrue($route->has_any_validatable_parameter());
500
 
501
        // A pathtype is a validatable param.
502
        $route = new route(
503
            queryparams: [
504
                new query_parameter(
505
                    name: 'example',
506
                    type: param::INT,
507
                ),
508
            ],
509
        );
510
        $this->assertTrue($route->has_any_validatable_parameter());
511
 
512
        // A request body is a validatable param.
513
        $route = new route(
514
            requestbody: new request_body(),
515
        );
516
        $this->assertTrue($route->has_any_validatable_parameter());
517
    }
518
 
519
    /**
520
     * Test cookie control.
521
     */
522
    public function test_cookies(): void {
523
        // By default we allow cookie access.
524
        $route = new route();
525
        $this->assertTrue($route->cookies);
526
    }
527
 
528
    /**
529
     * Test abort_after_config control.
530
     */
531
    public function test_abort_after_config(): void {
532
        // By default we do not abort after config.
533
        $route = new route();
534
        $this->assertFalse($route->abortafterconfig);
535
    }
536
 
537
    public function test_get_responses(): void {
538
        $route = new route(
539
            responses: [
540
                new response(
541
                    statuscode: 201,
542
                    description: 'Example response',
543
                ),
544
                new empty_response(),
545
            ],
546
        );
547
 
548
        $this->assertCount(2, $route->get_responses());
549
 
550
        $this->assertNull($route->get_response_with_status_code(200));
551
        $this->assertInstanceOf(
552
            empty_response::class,
553
            $route->get_response_with_status_code(204),
554
        );
555
        $this->assertInstanceOf(
556
            response::class,
557
            $route->get_response_with_status_code(201),
558
        );
559
        $this->assertEquals('Example response', $route->get_response_with_status_code(201)->description);
560
    }
561
}