Proyectos de Subversion Moodle

Rev

Autoría | Ultima modificación | Ver Log |

<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

namespace core\router;

use core\param;
use core\router\response\empty_response;
use core\router\route;
use core\router\schema\parameters\header_object;
use core\router\schema\parameters\path_parameter;
use core\router\schema\parameters\query_parameter;
use core\router\schema\request_body;
use core\router\schema\response\response;
use core\tests\router\route_testcase;

/**
 * Tests for user preference API handler.
 *
 * @package   core
 * @copyright Andrew Lyons <andrew@nicols.co.uk>
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 * @covers    \core\router\route
 */
final class route_test extends route_testcase {
    /**
     * Test that the Attribute is configured correctly.
     */
    public function test_attributes(): void {
        $route = new \ReflectionClass(route::class);
        $this->assertNotEmpty($route->getAttributes());

        $this->assertNotEmpty($route->getAttributes(\Attribute::class));
        $attributes = $route->getAttributes(\Attribute::class);
        $this->assertCount(1, $attributes);
        $attribute = reset($attributes);
        $flags = $attribute->getArguments()[0];

        // This can only be set on class, and method.
        $this->assertEquals(\Attribute::TARGET_CLASS, $flags & \Attribute::TARGET_CLASS);
        $this->assertEquals(\Attribute::TARGET_METHOD, $flags & \Attribute::TARGET_METHOD);

        // Only one per method or class allowed.
        $this->assertEquals(0, \Attribute::IS_REPEATABLE & $flags);

        // Yes, this is a poor test, but if someone wants to extend this attribute in future,
        // they need to write appropriate tests for it.
        $this->assertEquals(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD, $flags);
    }

    /**
     * Test that path setting and getting works as expected.
     */
    public function test_get_path(): void {
        $route = new route(
            path: '/example',
        );

        $this->assertEquals('/example', $route->get_path());

        // And with a parent.
        $child = new route(
            path: '/child/path',
        );
        $child->set_parent($route);
        $this->assertEquals('/example/child/path', $child->get_path());

        // But the parent is not changed in any way.
        $this->assertEquals('/example', $route->get_path());
    }


    /**
     * Test the default method.
     */
    public function test_get_methods(): void {
        // No method specified.
        $route = new route();
        $this->assertNull($route->get_methods());

        // With a method.
        $route = new route(
            method: 'POST',
        );
        $this->assertEquals(['POST'], $route->get_methods());

        // An array of methods.
        $route = new route(
            method: ['POST', 'PUT'],
        );
        $this->assertEquals(['POST', 'PUT'], $route->get_methods());

        // A route which inherits its method from its parent.
        $child = new route();
        $child->set_parent($route);
        $this->assertEquals(['POST', 'PUT'], $child->get_methods());

        // A child route will merge its own methods with its parents.
        $child = new route(
            method: 'GET',
        );
        $child->set_parent($route);
        $this->assertEquals(['GET', 'POST', 'PUT'], $child->get_methods());

        // A child route which shares some will not duplicate.
        $child = new route(
            method: ['GET', 'PUT'],
        );
        $child->set_parent($route);
        $this->assertEquals(['GET', 'POST', 'PUT'], $child->get_methods());
    }

    /**
     * Ensure that pathtypes and queryparams accept query parameters correctly.
     */
    public function test_params_are_params(): void {
        $route = new route(
            pathtypes: [
                new path_parameter(
                    name: 'example',
                    type: param::RAW,
                ),
                new path_parameter(
                    name: 'another',
                    type: param::INT,
                ),
            ],
            queryparams: [
                new query_parameter(
                    name: 'example',
                    type: param::RAW,
                ),
                new query_parameter(
                    name: 'another',
                    type: param::INT,
                ),
            ],
        );
        $this->assertInstanceOf(route::class, $route);
    }

    /**
     * Ensure that pathtypes and queryparams do not accept the wrong type of parameter.
     *
     * @dataProvider invalid_constructor_param_types
     * @param array $args
     */
    public function test_params_not_params(array $args): void {
        $this->expectException(\coding_exception::class);
        new route(...$args);
    }

    /**
     * Data provider for test_params_not_params.
     *
     * @return array
     */
    public static function invalid_constructor_param_types(): array {
        return [
            'not a param at all in queryparams' => [
                'args' => [
                    'queryparams' => [
                        new query_parameter(
                            name: 'another',
                            type: param::INT,
                        ),
                        new \stdClass(),
                    ],
                ],
            ],
            'not a param at all in pathtypes' => [
                'args' => [
                    'pathtypes' => [
                        new path_parameter(
                            name: 'another',
                            type: param::INT,
                        ),
                        new \stdClass(),
                    ],
                ],
            ],
            'not a param at all in headerparams' => [
                'args' => [
                    'headerparams' => [
                        new header_object(
                            name: 'another',
                            type: param::INT,
                        ),
                        new \stdClass(),
                    ],
                ],
            ],
            'path_parameter in queryparams' => [
                'args' => [
                    'queryparams' => [
                        new path_parameter(
                            name: 'example',
                            type: param::RAW,
                        ),
                        new query_parameter(
                            name: 'another',
                            type: param::INT,
                        ),
                    ],
                ],
            ],
            'query_parameter in pathtype' => [
                'args' => [
                    'pathtypes' => [
                        new path_parameter(
                            name: 'example',
                            type: param::RAW,
                        ),
                        new query_parameter(
                            name: 'another',
                            type: param::INT,
                        ),
                    ],
                ],
            ],
            'query_parameter in header' => [
                'args' => [
                    'headerparams' => [
                        new path_parameter(
                            name: 'example',
                            type: param::RAW,
                        ),
                        new query_parameter(
                            name: 'another',
                            type: param::INT,
                        ),
                    ],
                ],
            ],
        ];
    }

    public function test_get_path_parameters(): void {
        // No parameters at all.
        $route = new route();
        $this->assertEmpty($route->get_path_parameters());

        $child = new route();
        $child->set_parent($route);
        $this->assertEmpty($child->get_path_parameters());

        // A route with a single parameter.
        $route = new route(
            pathtypes: [
                new path_parameter(
                    name: 'example',
                    type: param::SAFEPATH,
                ),
            ],
        );
        $params = $route->get_path_parameters();
        $this->assertCount(1, $params);
        $this->assertArrayHasKey('example', $params);
        $this->assertInstanceOf(path_parameter::class, $params['example']);
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());

        // A route with a multiple parameters.
        $route = new route(
            pathtypes: [
                new path_parameter(
                    name: 'example',
                    type: param::SAFEPATH,
                ),
                new path_parameter(
                    name: 'another',
                    type: param::INT,
                ),
            ],
        );
        $params = $route->get_path_parameters();
        $this->assertCount(2, $params);
        $this->assertArrayHasKey('example', $params);
        $this->assertArrayHasKey('another', $params);
        $this->assertInstanceOf(path_parameter::class, $params['example']);
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
        $this->assertInstanceOf(path_parameter::class, $params['another']);
        $this->assertEquals(param::INT, $params['another']->get_type());

        // A child will also inhereit any params from the parent.
        $child = new route(
            pathtypes: [
                new path_parameter(
                    name: 'childparam',
                    type: param::COMPONENT,
                ),
            ],
        );
        $child->set_parent($route);
        $params = $child->get_path_parameters();
        $this->assertCount(3, $params);
        $this->assertArrayHasKey('example', $params);
        $this->assertArrayHasKey('another', $params);
        $this->assertArrayHasKey('childparam', $params);
        $this->assertInstanceOf(path_parameter::class, $params['example']);
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
        $this->assertInstanceOf(path_parameter::class, $params['another']);
        $this->assertEquals(param::INT, $params['another']->get_type());
        $this->assertInstanceOf(path_parameter::class, $params['childparam']);
        $this->assertEquals(param::COMPONENT, $params['childparam']->get_type());
    }

    public function test_get_header_parameters(): void {
        // No parameters at all.
        $route = new route();
        $this->assertEmpty($route->get_header_parameters());

        $child = new route();
        $child->set_parent($route);
        $this->assertEmpty($child->get_header_parameters());

        // A route with a single parameter.
        $route = new route(
            headerparams: [
                new header_object(
                    name: 'example',
                    type: param::SAFEPATH,
                ),
            ],
        );
        $params = $route->get_header_parameters();
        $this->assertCount(1, $params);
        $this->assertArrayHasKey('example', $params);
        $this->assertInstanceOf(header_object::class, $params['example']);
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());

        // A route with a multiple parameters.
        $route = new route(
            headerparams: [
                new header_object(
                    name: 'example',
                    type: param::SAFEPATH,
                ),
                new header_object(
                    name: 'another',
                    type: param::INT,
                ),
            ],
        );
        $params = $route->get_header_parameters();
        $this->assertCount(2, $params);
        $this->assertArrayHasKey('example', $params);
        $this->assertArrayHasKey('another', $params);
        $this->assertInstanceOf(header_object::class, $params['example']);
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
        $this->assertInstanceOf(header_object::class, $params['another']);
        $this->assertEquals(param::INT, $params['another']->get_type());

        // A child will also inhereit any params from the parent.
        $child = new route(
            headerparams: [
                new header_object(
                    name: 'childparam',
                    type: param::COMPONENT,
                ),
            ],
        );
        $child->set_parent($route);
        $params = $child->get_header_parameters();
        $this->assertCount(3, $params);
        $this->assertArrayHasKey('example', $params);
        $this->assertArrayHasKey('another', $params);
        $this->assertArrayHasKey('childparam', $params);
        $this->assertInstanceOf(header_object::class, $params['example']);
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
        $this->assertInstanceOf(header_object::class, $params['another']);
        $this->assertEquals(param::INT, $params['another']->get_type());
        $this->assertInstanceOf(header_object::class, $params['childparam']);
        $this->assertEquals(param::COMPONENT, $params['childparam']->get_type());
    }

    public function test_get_query_parameters(): void {
        // No parameters at all.
        $route = new route();
        $this->assertEmpty($route->get_query_parameters());

        $child = new route();
        $child->set_parent($route);
        $this->assertEmpty($child->get_query_parameters());

        // A route with a single parameter.
        $route = new route(
            queryparams: [
                new query_parameter(
                    name: 'example',
                    type: param::SAFEPATH,
                ),
            ],
        );
        $params = $route->get_query_parameters();
        $this->assertCount(1, $params);
        $this->assertArrayHasKey('example', $params);
        $this->assertInstanceOf(query_parameter::class, $params['example']);
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());

        // A route with a multiple parameters.
        $route = new route(
            queryparams: [
                new query_parameter(
                    name: 'example',
                    type: param::SAFEPATH,
                ),
                new query_parameter(
                    name: 'another',
                    type: param::INT,
                ),
            ],
        );
        $params = $route->get_query_parameters();
        $this->assertCount(2, $params);
        $this->assertArrayHasKey('example', $params);
        $this->assertArrayHasKey('another', $params);
        $this->assertInstanceOf(query_parameter::class, $params['example']);
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
        $this->assertInstanceOf(query_parameter::class, $params['another']);
        $this->assertEquals(param::INT, $params['another']->get_type());

        // A child will also inhereit any params from the parent.
        $child = new route(
            queryparams: [
                new query_parameter(
                    name: 'childparam',
                    type: param::COMPONENT,
                ),
            ],
        );
        $child->set_parent($route);
        $params = $child->get_query_parameters();
        $this->assertCount(3, $params);
        $this->assertArrayHasKey('example', $params);
        $this->assertArrayHasKey('another', $params);
        $this->assertArrayHasKey('childparam', $params);
        $this->assertInstanceOf(query_parameter::class, $params['example']);
        $this->assertEquals(param::SAFEPATH, $params['example']->get_type());
        $this->assertInstanceOf(query_parameter::class, $params['another']);
        $this->assertEquals(param::INT, $params['another']->get_type());
        $this->assertInstanceOf(query_parameter::class, $params['childparam']);
        $this->assertEquals(param::COMPONENT, $params['childparam']->get_type());
    }

    /**
     * Test that has_request_body works as expected.
     */
    public function test_has_request_body(): void {
        $route = new route();
        $this->assertFalse($route->has_request_body());

        $route = new route(
            requestbody: new request_body(),
        );
        $this->assertTrue($route->has_request_body());
    }

    public function test_get_request_body(): void {
        $route = new route();
        $this->assertNull($route->get_request_body());

        $body = new request_body();
        $route = new route(
            requestbody: $body,
        );
        $this->assertEquals($body, $route->get_request_body());

    }

    /**
     * Ensure that has_any_validatable_parameter checks the param types.
     */
    public function test_has_any_validatable_parameter(): void {
        // No validatable params.
        $route = new route();
        $this->assertFalse($route->has_any_validatable_parameter());

        // A pathtype is a validatable param.
        $route = new route(
            pathtypes: [
                new path_parameter(
                    name: 'example',
                    type: param::INT,
                ),
            ],
        );
        $this->assertTrue($route->has_any_validatable_parameter());

        // A pathtype is a validatable param.
        $route = new route(
            queryparams: [
                new query_parameter(
                    name: 'example',
                    type: param::INT,
                ),
            ],
        );
        $this->assertTrue($route->has_any_validatable_parameter());

        // A request body is a validatable param.
        $route = new route(
            requestbody: new request_body(),
        );
        $this->assertTrue($route->has_any_validatable_parameter());
    }

    /**
     * Test cookie control.
     */
    public function test_cookies(): void {
        // By default we allow cookie access.
        $route = new route();
        $this->assertTrue($route->cookies);
    }

    /**
     * Test abort_after_config control.
     */
    public function test_abort_after_config(): void {
        // By default we do not abort after config.
        $route = new route();
        $this->assertFalse($route->abortafterconfig);
    }

    public function test_get_responses(): void {
        $route = new route(
            responses: [
                new response(
                    statuscode: 201,
                    description: 'Example response',
                ),
                new empty_response(),
            ],
        );

        $this->assertCount(2, $route->get_responses());

        $this->assertNull($route->get_response_with_status_code(200));
        $this->assertInstanceOf(
            empty_response::class,
            $route->get_response_with_status_code(204),
        );
        $this->assertInstanceOf(
            response::class,
            $route->get_response_with_status_code(201),
        );
        $this->assertEquals('Example response', $route->get_response_with_status_code(201)->description);
    }
}