You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
658 lines
16 KiB
658 lines
16 KiB
<?php |
|
|
|
namespace yiiunit\framework\web; |
|
|
|
use yii\web\UrlManager; |
|
use yii\web\UrlRule; |
|
use yii\web\Request; |
|
use yiiunit\TestCase; |
|
|
|
/** |
|
* @group web |
|
*/ |
|
class UrlRuleTest extends TestCase |
|
{ |
|
public function testCreateUrl() |
|
{ |
|
$manager = new UrlManager(['cache' => null]); |
|
$suites = $this->getTestsForCreateUrl(); |
|
foreach ($suites as $i => $suite) { |
|
list ($name, $config, $tests) = $suite; |
|
$rule = new UrlRule($config); |
|
foreach ($tests as $j => $test) { |
|
list ($route, $params, $expected) = $test; |
|
$url = $rule->createUrl($manager, $route, $params); |
|
$this->assertEquals($expected, $url, "Test#$i-$j: $name"); |
|
} |
|
} |
|
} |
|
|
|
public function testParseRequest() |
|
{ |
|
$manager = new UrlManager(['cache' => null]); |
|
$request = new Request(['hostInfo' => 'http://en.example.com']); |
|
$suites = $this->getTestsForParseRequest(); |
|
foreach ($suites as $i => $suite) { |
|
list ($name, $config, $tests) = $suite; |
|
$rule = new UrlRule($config); |
|
foreach ($tests as $j => $test) { |
|
$request->pathInfo = $test[0]; |
|
$route = $test[1]; |
|
$params = isset($test[2]) ? $test[2] : []; |
|
$result = $rule->parseRequest($manager, $request); |
|
if ($route === false) { |
|
$this->assertFalse($result, "Test#$i-$j: $name"); |
|
} else { |
|
$this->assertEquals([$route, $params], $result, "Test#$i-$j: $name"); |
|
} |
|
} |
|
} |
|
} |
|
|
|
protected function getTestsForCreateUrl() |
|
{ |
|
// structure of each test |
|
// message for the test |
|
// config for the URL rule |
|
// list of inputs and outputs |
|
// route |
|
// params |
|
// expected output |
|
return [ |
|
[ |
|
'empty pattern', |
|
[ |
|
'pattern' => '', |
|
'route' => 'post/index', |
|
], |
|
[ |
|
['post/index', [], ''], |
|
['comment/index', [], false], |
|
['post/index', ['page' => 1], '?page=1'], |
|
], |
|
], |
|
[ |
|
'without param', |
|
[ |
|
'pattern' => 'posts', |
|
'route' => 'post/index', |
|
], |
|
[ |
|
['post/index', [], 'posts'], |
|
['comment/index', [], false], |
|
['post/index', ['page' => 1], 'posts?page=1'], |
|
], |
|
], |
|
[ |
|
'parsing only', |
|
[ |
|
'pattern' => 'posts', |
|
'route' => 'post/index', |
|
'mode' => UrlRule::PARSING_ONLY, |
|
], |
|
[ |
|
['post/index', [], false], |
|
], |
|
], |
|
[ |
|
'with param', |
|
[ |
|
'pattern' => 'post/<page>', |
|
'route' => 'post/index', |
|
], |
|
[ |
|
['post/index', [], false], |
|
['comment/index', [], false], |
|
['post/index', ['page' => 1], 'post/1'], |
|
['post/index', ['page' => 1, 'tag' => 'a'], 'post/1?tag=a'], |
|
], |
|
], |
|
[ |
|
'with param requirement', |
|
[ |
|
'pattern' => 'post/<page:\d+>', |
|
'route' => 'post/index', |
|
], |
|
[ |
|
['post/index', ['page' => 'abc'], false], |
|
['post/index', ['page' => 1], 'post/1'], |
|
['post/index', ['page' => 1, 'tag' => 'a'], 'post/1?tag=a'], |
|
], |
|
], |
|
[ |
|
'with multiple params', |
|
[ |
|
'pattern' => 'post/<page:\d+>-<tag>', |
|
'route' => 'post/index', |
|
], |
|
[ |
|
['post/index', ['page' => '1abc'], false], |
|
['post/index', ['page' => 1], false], |
|
['post/index', ['page' => 1, 'tag' => 'a'], 'post/1-a'], |
|
], |
|
], |
|
[ |
|
'with optional param', |
|
[ |
|
'pattern' => 'post/<page:\d+>/<tag>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1], |
|
], |
|
[ |
|
['post/index', ['page' => 1], false], |
|
['post/index', ['page' => '1abc', 'tag' => 'a'], false], |
|
['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], |
|
['post/index', ['page' => 2, 'tag' => 'a'], 'post/2/a'], |
|
], |
|
], |
|
[ |
|
'with optional param not in pattern', |
|
[ |
|
'pattern' => 'post/<tag>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1], |
|
], |
|
[ |
|
['post/index', ['page' => 1], false], |
|
['post/index', ['page' => '1abc', 'tag' => 'a'], false], |
|
['post/index', ['page' => 2, 'tag' => 'a'], false], |
|
['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], |
|
], |
|
], |
|
[ |
|
'multiple optional params', |
|
[ |
|
'pattern' => 'post/<page:\d+>/<tag>/<sort:yes|no>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1, 'sort' => 'yes'], |
|
], |
|
[ |
|
['post/index', ['page' => 1], false], |
|
['post/index', ['page' => '1abc', 'tag' => 'a'], false], |
|
['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'YES'], false], |
|
['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'yes'], 'post/a'], |
|
['post/index', ['page' => 2, 'tag' => 'a', 'sort' => 'yes'], 'post/2/a'], |
|
['post/index', ['page' => 2, 'tag' => 'a', 'sort' => 'no'], 'post/2/a/no'], |
|
['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'no'], 'post/a/no'], |
|
], |
|
], |
|
[ |
|
'optional param and required param separated by dashes', |
|
[ |
|
'pattern' => 'post/<page:\d+>-<tag>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1], |
|
], |
|
[ |
|
['post/index', ['page' => 1], false], |
|
['post/index', ['page' => '1abc', 'tag' => 'a'], false], |
|
['post/index', ['page' => 1, 'tag' => 'a'], 'post/-a'], |
|
['post/index', ['page' => 2, 'tag' => 'a'], 'post/2-a'], |
|
], |
|
], |
|
[ |
|
'optional param at the end', |
|
[ |
|
'pattern' => 'post/<tag>/<page:\d+>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1], |
|
], |
|
[ |
|
['post/index', ['page' => 1], false], |
|
['post/index', ['page' => '1abc', 'tag' => 'a'], false], |
|
['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], |
|
['post/index', ['page' => 2, 'tag' => 'a'], 'post/a/2'], |
|
], |
|
], |
|
[ |
|
'consecutive optional params', |
|
[ |
|
'pattern' => 'post/<page:\d+>/<tag>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1, 'tag' => 'a'], |
|
], |
|
[ |
|
['post/index', ['page' => 1], false], |
|
['post/index', ['page' => '1abc', 'tag' => 'a'], false], |
|
['post/index', ['page' => 1, 'tag' => 'a'], 'post'], |
|
['post/index', ['page' => 2, 'tag' => 'a'], 'post/2'], |
|
['post/index', ['page' => 1, 'tag' => 'b'], 'post/b'], |
|
['post/index', ['page' => 2, 'tag' => 'b'], 'post/2/b'], |
|
], |
|
], |
|
[ |
|
'consecutive optional params separated by dash', |
|
[ |
|
'pattern' => 'post/<page:\d+>-<tag>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1, 'tag' => 'a'], |
|
], |
|
[ |
|
['post/index', ['page' => 1], false], |
|
['post/index', ['page' => '1abc', 'tag' => 'a'], false], |
|
['post/index', ['page' => 1, 'tag' => 'a'], 'post/-'], |
|
['post/index', ['page' => 1, 'tag' => 'b'], 'post/-b'], |
|
['post/index', ['page' => 2, 'tag' => 'a'], 'post/2-'], |
|
['post/index', ['page' => 2, 'tag' => 'b'], 'post/2-b'], |
|
], |
|
], |
|
[ |
|
'route has parameters', |
|
[ |
|
'pattern' => '<controller>/<action>', |
|
'route' => '<controller>/<action>', |
|
'defaults' => [], |
|
], |
|
[ |
|
['post/index', ['page' => 1], 'post/index?page=1'], |
|
['module/post/index', [], false], |
|
], |
|
], |
|
[ |
|
'route has parameters with regex', |
|
[ |
|
'pattern' => '<controller:post|comment>/<action>', |
|
'route' => '<controller>/<action>', |
|
'defaults' => [], |
|
], |
|
[ |
|
['post/index', ['page' => 1], 'post/index?page=1'], |
|
['comment/index', ['page' => 1], 'comment/index?page=1'], |
|
['test/index', ['page' => 1], false], |
|
['post', [], false], |
|
['module/post/index', [], false], |
|
['post/index', ['controller' => 'comment'], 'post/index?controller=comment'], |
|
], |
|
], |
|
[ |
|
'route has default parameter', |
|
[ |
|
'pattern' => '<controller:post|comment>/<action>', |
|
'route' => '<controller>/<action>', |
|
'defaults' => ['action' => 'index'], |
|
], |
|
[ |
|
['post/view', ['page' => 1], 'post/view?page=1'], |
|
['comment/view', ['page' => 1], 'comment/view?page=1'], |
|
['test/view', ['page' => 1], false], |
|
['test/index', ['page' => 1], false], |
|
['post/index', ['page' => 1], 'post?page=1'], |
|
], |
|
], |
|
[ |
|
'empty pattern with suffix', |
|
[ |
|
'pattern' => '', |
|
'route' => 'post/index', |
|
'suffix' => '.html', |
|
], |
|
[ |
|
['post/index', [], ''], |
|
['comment/index', [], false], |
|
['post/index', ['page' => 1], '?page=1'], |
|
], |
|
], |
|
[ |
|
'regular pattern with suffix', |
|
[ |
|
'pattern' => 'posts', |
|
'route' => 'post/index', |
|
'suffix' => '.html', |
|
], |
|
[ |
|
['post/index', [], 'posts.html'], |
|
['comment/index', [], false], |
|
['post/index', ['page' => 1], 'posts.html?page=1'], |
|
], |
|
], |
|
[ |
|
'empty pattern with slash suffix', |
|
[ |
|
'pattern' => '', |
|
'route' => 'post/index', |
|
'suffix' => '/', |
|
], |
|
[ |
|
['post/index', [], ''], |
|
['comment/index', [], false], |
|
['post/index', ['page' => 1], '?page=1'], |
|
], |
|
], |
|
[ |
|
'regular pattern with slash suffix', |
|
[ |
|
'pattern' => 'posts', |
|
'route' => 'post/index', |
|
'suffix' => '/', |
|
], |
|
[ |
|
['post/index', [], 'posts/'], |
|
['comment/index', [], false], |
|
['post/index', ['page' => 1], 'posts/?page=1'], |
|
], |
|
], |
|
[ |
|
'with host info', |
|
[ |
|
'pattern' => 'post/<page:\d+>/<tag>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1], |
|
'host' => 'http://<lang:en|fr>.example.com', |
|
], |
|
[ |
|
['post/index', ['page' => 1, 'tag' => 'a'], false], |
|
['post/index', ['page' => 1, 'tag' => 'a', 'lang' => 'en'], 'http://en.example.com/post/a'], |
|
], |
|
], |
|
]; |
|
} |
|
|
|
protected function getTestsForParseRequest() |
|
{ |
|
// structure of each test |
|
// message for the test |
|
// config for the URL rule |
|
// list of inputs and outputs |
|
// pathInfo |
|
// expected route, or false if the rule doesn't apply |
|
// expected params, or not set if empty |
|
return [ |
|
[ |
|
'empty pattern', |
|
[ |
|
'pattern' => '', |
|
'route' => 'post/index', |
|
], |
|
[ |
|
['', 'post/index'], |
|
['a', false], |
|
], |
|
], |
|
[ |
|
'without param', |
|
[ |
|
'pattern' => 'posts', |
|
'route' => 'post/index', |
|
], |
|
[ |
|
['posts', 'post/index'], |
|
['a', false], |
|
], |
|
], |
|
[ |
|
'with dot', // https://github.com/yiisoft/yii/issues/2945 |
|
[ |
|
'pattern' => 'posts.html', |
|
'route' => 'post/index', |
|
], |
|
[ |
|
['posts.html', 'post/index'], |
|
['postsahtml', false], |
|
], |
|
], |
|
[ |
|
'creation only', |
|
[ |
|
'pattern' => 'posts', |
|
'route' => 'post/index', |
|
'mode' => UrlRule::CREATION_ONLY, |
|
], |
|
[ |
|
['posts', false], |
|
], |
|
], |
|
[ |
|
'with param', |
|
[ |
|
'pattern' => 'post/<page>', |
|
'route' => 'post/index', |
|
], |
|
[ |
|
['post/1', 'post/index', ['page' => '1']], |
|
['post/a', 'post/index', ['page' => 'a']], |
|
['post', false], |
|
['posts', false], |
|
], |
|
], |
|
[ |
|
'with param requirement', |
|
[ |
|
'pattern' => 'post/<page:\d+>', |
|
'route' => 'post/index', |
|
], |
|
[ |
|
['post/1', 'post/index', ['page' => '1']], |
|
['post/a', false], |
|
['post/1/a', false], |
|
], |
|
], |
|
[ |
|
'with multiple params', |
|
[ |
|
'pattern' => 'post/<page:\d+>-<tag>', |
|
'route' => 'post/index', |
|
], |
|
[ |
|
['post/1-a', 'post/index', ['page' => '1', 'tag' => 'a']], |
|
['post/a', false], |
|
['post/1', false], |
|
['post/1/a', false], |
|
], |
|
], |
|
[ |
|
'with optional param', |
|
[ |
|
'pattern' => 'post/<page:\d+>/<tag>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1], |
|
], |
|
[ |
|
['post/1/a', 'post/index', ['page' => '1', 'tag' => 'a']], |
|
['post/2/a', 'post/index', ['page' => '2', 'tag' => 'a']], |
|
['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], |
|
['post/1', 'post/index', ['page' => '1', 'tag' => '1']], |
|
], |
|
], |
|
[ |
|
'with optional param not in pattern', |
|
[ |
|
'pattern' => 'post/<tag>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1], |
|
], |
|
[ |
|
['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], |
|
['post/1', 'post/index', ['page' => '1', 'tag' => '1']], |
|
['post', false], |
|
], |
|
], |
|
[ |
|
'multiple optional params', |
|
[ |
|
'pattern' => 'post/<page:\d+>/<tag>/<sort:yes|no>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1, 'sort' => 'yes'], |
|
], |
|
[ |
|
['post/1/a/yes', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'yes']], |
|
['post/1/a/no', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'no']], |
|
['post/2/a/no', 'post/index', ['page' => '2', 'tag' => 'a', 'sort' => 'no']], |
|
['post/2/a', 'post/index', ['page' => '2', 'tag' => 'a', 'sort' => 'yes']], |
|
['post/a/no', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'no']], |
|
['post/a', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'yes']], |
|
['post', false], |
|
], |
|
], |
|
[ |
|
'optional param and required param separated by dashes', |
|
[ |
|
'pattern' => 'post/<page:\d+>-<tag>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1], |
|
], |
|
[ |
|
['post/1-a', 'post/index', ['page' => '1', 'tag' => 'a']], |
|
['post/2-a', 'post/index', ['page' => '2', 'tag' => 'a']], |
|
['post/-a', 'post/index', ['page' => '1', 'tag' => 'a']], |
|
['post/a', false], |
|
['post-a', false], |
|
], |
|
], |
|
[ |
|
'optional param at the end', |
|
[ |
|
'pattern' => 'post/<tag>/<page:\d+>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1], |
|
], |
|
[ |
|
['post/a/1', 'post/index', ['page' => '1', 'tag' => 'a']], |
|
['post/a/2', 'post/index', ['page' => '2', 'tag' => 'a']], |
|
['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], |
|
['post/2', 'post/index', ['page' => '1', 'tag' => '2']], |
|
['post', false], |
|
], |
|
], |
|
[ |
|
'consecutive optional params', |
|
[ |
|
'pattern' => 'post/<page:\d+>/<tag>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1, 'tag' => 'a'], |
|
], |
|
[ |
|
['post/2/b', 'post/index', ['page' => '2', 'tag' => 'b']], |
|
['post/2', 'post/index', ['page' => '2', 'tag' => 'a']], |
|
['post', 'post/index', ['page' => '1', 'tag' => 'a']], |
|
['post/b', 'post/index', ['page' => '1', 'tag' => 'b']], |
|
['post//b', false], |
|
], |
|
], |
|
[ |
|
'consecutive optional params separated by dash', |
|
[ |
|
'pattern' => 'post/<page:\d+>-<tag>', |
|
'route' => 'post/index', |
|
'defaults' => ['page' => 1, 'tag' => 'a'], |
|
], |
|
[ |
|
['post/2-b', 'post/index', ['page' => '2', 'tag' => 'b']], |
|
['post/2-', 'post/index', ['page' => '2', 'tag' => 'a']], |
|
['post/-b', 'post/index', ['page' => '1', 'tag' => 'b']], |
|
['post/-', 'post/index', ['page' => '1', 'tag' => 'a']], |
|
['post', false], |
|
], |
|
], |
|
[ |
|
'route has parameters', |
|
[ |
|
'pattern' => '<controller>/<action>', |
|
'route' => '<controller>/<action>', |
|
'defaults' => [], |
|
], |
|
[ |
|
['post/index', 'post/index'], |
|
['module/post/index', false], |
|
], |
|
], |
|
[ |
|
'route has parameters with regex', |
|
[ |
|
'pattern' => '<controller:post|comment>/<action>', |
|
'route' => '<controller>/<action>', |
|
'defaults' => [], |
|
], |
|
[ |
|
['post/index', 'post/index'], |
|
['comment/index', 'comment/index'], |
|
['test/index', false], |
|
['post', false], |
|
['module/post/index', false], |
|
], |
|
], |
|
[ |
|
'route has default parameter', |
|
[ |
|
'pattern' => '<controller:post|comment>/<action>', |
|
'route' => '<controller>/<action>', |
|
'defaults' => ['action' => 'index'], |
|
], |
|
[ |
|
['post/view', 'post/view'], |
|
['comment/view', 'comment/view'], |
|
['test/view', false], |
|
['post', 'post/index'], |
|
['posts', false], |
|
['test', false], |
|
['index', false], |
|
], |
|
], |
|
[ |
|
'empty pattern with suffix', |
|
[ |
|
'pattern' => '', |
|
'route' => 'post/index', |
|
'suffix' => '.html', |
|
], |
|
[ |
|
['', 'post/index'], |
|
['.html', false], |
|
['a.html', false], |
|
], |
|
], |
|
[ |
|
'regular pattern with suffix', |
|
[ |
|
'pattern' => 'posts', |
|
'route' => 'post/index', |
|
'suffix' => '.html', |
|
], |
|
[ |
|
['posts.html', 'post/index'], |
|
['posts', false], |
|
['posts.HTML', false], |
|
['a.html', false], |
|
['a', false], |
|
], |
|
], |
|
[ |
|
'empty pattern with slash suffix', |
|
[ |
|
'pattern' => '', |
|
'route' => 'post/index', |
|
'suffix' => '/', |
|
], |
|
[ |
|
['', 'post/index'], |
|
['a', false], |
|
], |
|
], |
|
[ |
|
'regular pattern with slash suffix', |
|
[ |
|
'pattern' => 'posts', |
|
'route' => 'post/index', |
|
'suffix' => '/', |
|
], |
|
[ |
|
['posts/', 'post/index'], |
|
['posts', false], |
|
['a', false], |
|
], |
|
], |
|
[ |
|
'with host info', |
|
[ |
|
'pattern' => 'post/<page:\d+>', |
|
'route' => 'post/index', |
|
'host' => 'http://<lang:en|fr>.example.com', |
|
], |
|
[ |
|
['post/1', 'post/index', ['page' => '1', 'lang' => 'en']], |
|
['post/a', false], |
|
['post/1/a', false], |
|
], |
|
], |
|
]; |
|
} |
|
}
|
|
|