<commit_before><?php
declare(strict_types=1);

/**
 * A KnpMenu seasoned menu plugin for CakePHP.
 *
 * @see https://github.com/icings/menu
 */

namespace Icings\Menu\Test\TestCase\Matcher\Voter;

use Cake\Core\Configure;
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\TestSuite\TestCase;
use Cake\Utility\Hash;
use Icings\Menu\Matcher\Voter\FuzzyRouteVoter;
use Icings\Menu\TestSuite\RequestFactoryTrait;
use Knp\Menu\ItemInterface;
use PHPUnit\Framework\MockObject\MockObject;

class FuzzyRouteVoterTest extends TestCase
{
    use RequestFactoryTrait;

    public function setUp(): void
    {
        parent::setUp();

        Router::scope('/', function (RouteBuilder $routes) {
            $routes->setExtensions(['json']);
            $routes->setRouteClass(DashedRoute::class);

            $routes->connect('/named', [
                'controller' => 'Named',
                'action' => 'index'
            ], [
                '_name' => 'named'
            ]);

            $routes->connect('/named/:element', [
                'controller' => 'Named',
                'action' => 'index'
            ], [
                'pass' => ['element'],
                '_name' => 'namedWithElement'
            ]);

            $routes->connect('/:controller');
            $routes->connect('/:controller/:action');
            $routes->connect('/:controller/:action/:id', [], [
                'id' => Router::ID,
                'pass' => ['id']
            ]);
            $routes->connect('/:controller/:action/:id/:slug', [], [
                'id' => Router::ID,
                'pass' => ['id', 'slug']
            ]);

            $routes->connect('/special', [
                'controller' => 'Special',
                'action' => 'index',
                'specialKey' => [
                    'foo', 123, 'a' => 'a', 'b' => 'b'
                ]
            ]);

            $routes->prefix('PrefixName', function (RouteBuilder $routes) {
                $routes->connect('/:controller/:action');
            });

            $routes->plugin('PluginName', function (RouteBuilder $routes) {
                $routes->connect('/:controller/:action');
            });
        });
    }

    /**
     * @return array
     */
    public function paramsDataProvider()
    {
        $provider = [
            'Controller only request' => [
                '/controller',
                ['controller' => 'Controller', 'action' => 'index']
            ],
            'Controller + action request' => [
                '/controller/action',
                ['controller' => 'Controller', 'action' => 'action']
            ],
            'Request with passed element' => [
                '/controller/action/123',
                ['controller' => 'Controller', 'action' => 'action', 'id' => '123', '123']
            ],
            'Request with extension' => [
                '/controller/action.json',
                ['controller' => 'Controller', 'action' => 'action', '_ext' => 'json']
            ],
            'Request with query string' => [
                '/controller/action?query=value',
                ['controller' => 'Controller', 'action' => 'action', 'query' => 'value', '?' => ['query' => 'value']]
            ],
            'Request with numerical query string value' => [
                '/controller/action?query=123',
                ['controller' => 'Controller', 'action' => 'action', 'query' => '123', '?' => ['query' => '123']]
            ],
            'Request with float query string value' => [
                '/controller/action?query=12.3',
                ['controller' => 'Controller', 'action' => 'action', 'query' => '12.3', '?' => ['query' => '12.3']]
            ],
            'Prefix request' => [
                '/prefix-name/controller/action',
                ['controller' => 'Controller', 'action' => 'action', 'prefix' => 'prefix_name']
            ],
            'Plugin request' => [
                '/plugin-name/controller/action',
                ['controller' => 'Controller', 'action' => 'action', 'plugin' => 'PluginName']
            ],
            'Request route with custom defaults' => [
                '/special',
                ['controller' => 'Special', 'action' => 'index', 'specialKey' => ['foo', 123, 'a' => 'a', 'b' => 'b']]
            ],
        ];

        if (version_compare(Configure::version(), '3.5.11', '>=')) {
            $provider += [
                'Request named route' => [
                    '/named',
                    ['_name' => 'named', 'controller' => 'Named', 'action' => 'index']
                ],
                'Request named route with elements' => [
                    '/named/element',
                    ['_name' => 'namedWithElement', 'controller' => 'Named', 'action' => 'index', 'element' => 'element', 'element']
                ],
            ];
        } else {
            $provider += [
                'Request named route' => [
                    '/named',
                    ['controller' => 'Named', 'action' => 'index']
                ],
            ];
        }

        return $provider;
    }

    /**
     * @dataProvider paramsDataProvider
     *
     * @param string $requestUri
     * @param array $expected
     */
    public function testGetParams($requestUri, array $expected)
    {
        $request = static::createRequest($requestUri);
        $voter = new FuzzyRouteVoter($request);

        $defaults = [
            '?' => [],
            '_ext' => null,
            '_host' => 'localhost',
            '_method' => 'GET',
            'action' => null,
            'controller' => null,
            'plugin' => null
        ];

        $expected = Hash::merge($defaults, $expected);
        ksort($expected, \SORT_STRING);

        $actual = $voter->getParams();
        ksort($actual, \SORT_STRING);

        $this->assertSame($expected, $actual);
    }

    /**
     * @return array
     */
    public function matchingDataProvider()
    {
        $provider = [
            'No URL arrays set' => [
                null,
                '/controller/action',
                null
            ],

            'Exact matching URL array' => [
                [['controller' => 'Controller', 'action' => 'action']],
                '/controller/action',
                true
            ],
            'Wrong action name does not match' => [
                [['controller' => 'Controller', 'action' => 'other']],
                '/controller/action',
                false
            ],
            'Wrong controller name does not match' => [
                [['controller' => 'Other', 'action' => 'action']],
                '/controller/action',
                false
            ],
            'Elements do not require exact order' => [
                [['action' => 'action', 'controller' => 'Controller']],<commit_msg>Add test for request parameters without `pass` data.<commit_after><?php
declare(strict_types=1);

/**
 * A KnpMenu seasoned menu plugin for CakePHP.
 *
 * @see https://github.com/icings/menu
 */

namespace Icings\Menu\Test\TestCase\Matcher\Voter;

use Cake\Core\Configure;
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\TestSuite\TestCase;
use Cake\Utility\Hash;
use Icings\Menu\Matcher\Voter\FuzzyRouteVoter;
use Icings\Menu\TestSuite\RequestFactoryTrait;
use Knp\Menu\ItemInterface;
use PHPUnit\Framework\MockObject\MockObject;

class FuzzyRouteVoterTest extends TestCase
{
    use RequestFactoryTrait;

    public function setUp(): void
    {
        parent::setUp();

        Router::scope('/', function (RouteBuilder $routes) {
            $routes->setExtensions(['json']);
            $routes->setRouteClass(DashedRoute::class);

            $routes->connect('/named', [
                'controller' => 'Named',
                'action' => 'index'
            ], [
                '_name' => 'named'
            ]);

            $routes->connect('/named/:element', [
                'controller' => 'Named',
                'action' => 'index'
            ], [
                'pass' => ['element'],
                '_name' => 'namedWithElement'
            ]);

            $routes->connect('/:controller');
            $routes->connect('/:controller/:action');
            $routes->connect('/:controller/:action/:id', [], [
                'id' => Router::ID,
                'pass' => ['id']
            ]);
            $routes->connect('/:controller/:action/:id/:slug', [], [
                'id' => Router::ID,
                'pass' => ['id', 'slug']
            ]);

            $routes->connect('/special', [
                'controller' => 'Special',
                'action' => 'index',
                'specialKey' => [
                    'foo', 123, 'a' => 'a', 'b' => 'b'
                ]
            ]);

            $routes->prefix('PrefixName', function (RouteBuilder $routes) {
                $routes->connect('/:controller/:action');
            });

            $routes->plugin('PluginName', function (RouteBuilder $routes) {
                $routes->connect('/:controller/:action');
            });
        });
    }

    /**
     * @return array
     */
    public function paramsDataProvider()
    {
        $provider = [
            'Controller only request' => [
                '/controller',
                ['controller' => 'Controller', 'action' => 'index']
            ],
            'Controller + action request' => [
                '/controller/action',
                ['controller' => 'Controller', 'action' => 'action']
            ],
            'Request with passed element' => [
                '/controller/action/123',
                ['controller' => 'Controller', 'action' => 'action', 'id' => '123', '123']
            ],
            'Request with extension' => [
                '/controller/action.json',
                ['controller' => 'Controller', 'action' => 'action', '_ext' => 'json']
            ],
            'Request with query string' => [
                '/controller/action?query=value',
                ['controller' => 'Controller', 'action' => 'action', 'query' => 'value', '?' => ['query' => 'value']]
            ],
            'Request with numerical query string value' => [
                '/controller/action?query=123',
                ['controller' => 'Controller', 'action' => 'action', 'query' => '123', '?' => ['query' => '123']]
            ],
            'Request with float query string value' => [
                '/controller/action?query=12.3',
                ['controller' => 'Controller', 'action' => 'action', 'query' => '12.3', '?' => ['query' => '12.3']]
            ],
            'Prefix request' => [
                '/prefix-name/controller/action',
                ['controller' => 'Controller', 'action' => 'action', 'prefix' => 'prefix_name']
            ],
            'Plugin request' => [
                '/plugin-name/controller/action',
                ['controller' => 'Controller', 'action' => 'action', 'plugin' => 'PluginName']
            ],
            'Request route with custom defaults' => [
                '/special',
                ['controller' => 'Special', 'action' => 'index', 'specialKey' => ['foo', 123, 'a' => 'a', 'b' => 'b']]
            ],
        ];

        if (version_compare(Configure::version(), '3.5.11', '>=')) {
            $provider += [
                'Request named route' => [
                    '/named',
                    ['_name' => 'named', 'controller' => 'Named', 'action' => 'index']
                ],
                'Request named route with elements' => [
                    '/named/element',
                    ['_name' => 'namedWithElement', 'controller' => 'Named', 'action' => 'index', 'element' => 'element', 'element']
                ],
            ];
        } else {
            $provider += [
                'Request named route' => [
                    '/named',
                    ['controller' => 'Named', 'action' => 'index']
                ],
            ];
        }

        return $provider;
    }

    /**
     * @dataProvider paramsDataProvider
     *
     * @param string $requestUri
     * @param array $expected
     */
    public function testGetParams($requestUri, array $expected)
    {
        $request = static::createRequest($requestUri);
        $voter = new FuzzyRouteVoter($request);

        $defaults = [
            '?' => [],
            '_ext' => null,
            '_host' => 'localhost',
            '_method' => 'GET',
            'action' => null,
            'controller' => null,
            'plugin' => null
        ];

        $expected = Hash::merge($defaults, $expected);
        ksort($expected, \SORT_STRING);

        $actual = $voter->getParams();
        ksort($actual, \SORT_STRING);

        $this->assertSame($expected, $actual);
    }

    public function testGetParamsWithoutPass()
    {
        $request = static::createRequest('/controller/action');

        $params = $request->getAttribute('params');
        unset($params['pass']);
        $request = $request->withAttribute('params', $params);

        $voter = new FuzzyRouteVoter($request);

        $expected = [
            '?' => [],
            '_ext' => null,
            '_host' => 'localhost',
            '_method' => 'GET',
            'action' => 'action',
            'controller' => 'Controller',
            'plugin' => null
        ];
        $actual = $voter->getParams();

        $this->assertSame($expected, $actual);
    }

    /**
     * @return array
     */
    public function matchingDataProvider()
    {
        $provider = [
            'No URL arrays set' => [
                null,
                '/controller/action',
                null
            ],

            'Exact matching URL array' => [
                [['controller' => 'Controller', 'action' => 'action']],
                '/controller/action',
                true
            ],
            'Wrong action name does not match' => [
                [['controller' => 'Controller', 'action' => 'other']],
                '/controller/action',
                false
            ],
            'Wrong controller name does not match' => [
                [['controller' => 'Other', 'action' => 'action']],
                '/controller/action',
                false
            ],
            'Elements do not require exact order' => [
                [['action' => 'action', 'controller' => 'Controller']],
{'fraction_non_alphanumeric': 0.17366504020342244, 'fraction_numerical': 0.00522300872792248, 'mean_word_length': 1.5547752808988764, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 234, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5522006', 'n_tokens_mistral': 3930, 'n_tokens_neox': 3759, 'n_words': 763}