Files
yii2/tests/framework/web/UrlManagerParseUrlTest.php
Carsten Brandt 8faedcbd7c Refactored UrlManagerTest to cover more use cases
UrlManager is a complex class with a large bunch of options that needs
to be tested
and we had a few regressions in the past even though there are already a
lot of tests
covering it. Test coverage measured by lines does not help us determine
how good it is tested,
we need test coverage for every major path through the code.

I have refactored the UrlManager tests to reflect the different options
and cases to
have a better overview of which cases are covered and which are not.

UrlManager has two main operation modes:

- "default" url format, which is the simple case. These are covered by
  methods in `UrlManagerTest`.

- "pretty" url format. This is the complex case, which involves UrlRules
  and url parsing.
  I have created two separate classes for this case:
  Url creation for "pretty" url format is covered by
`UrlManagerCreateUrlTest`.
  Url parsing for "pretty" url format is covered by
`UrlManagerParseUrlTest`.

Each of the test classes have a `getUrlManager` method that creates a
UrlManager instance
with a specific configuration and certain variations in options.
It is also tested that options that are not relevant in a certain
operation mode have no effect on the result.

To make sure to not remove tests that have existed before, here is a map
of where code has been moved.
The following test methods existed in the [old test
class](4187718c14/tests/framework/web/UrlManagerTest.php):

- `testCreateUrl()` split between UrlManagerTest and
  UrlManagerCreateUrlTest variations should all be covered by
`variationsProvider()`.
- `testCreateUrlWithNullParams()` covered by UrlManagerCreateUrlTest by
  `testWithNullParams()`
- `testCreateUrlWithEmptyPattern()`
- `testCreateAbsoluteUrl()` covered in UrlManagerCreateUrlTest by new
  tests via `variationsProvider()`.
- `testCreateAbsoluteUrlWithSuffix()` covered in UrlManagerCreateUrlTest
  by `testAbsolutePatterns`.

- `testParseRequest()` covered by UrlManagerParseUrlTest, UrlNormalizer
  related parts moved to UrlNormalizerTest.
- `testParseRESTRequest()` moved to UrlManagerParseUrlTest
- `testHash()` covered in different tests in UrlManagerCreateUrlTest.
- `testMultipleHostsRules($host)` kept as is.

Before:

    $ vendor/bin/phpunit tests/framework/web/UrlManagerTest.php
    ...
    OK (12 tests, 89 assertions)

After:

    $ vendor/bin/phpunit tests/framework/web/UrlManager*.php
    ...
    OK (72 tests, 648 assertions)
2017-01-31 02:38:35 +01:00

343 lines
13 KiB
PHP

<?php
namespace yiiunit\framework\web;
use yii\web\Request;
use yii\web\UrlManager;
use yiiunit\TestCase;
/**
* This class implements the tests for URL parsing with "pretty" url format.
*
* See [[UrlManagerTest]] for tests with "default" URL format.
* See [[UrlManagerCreateUrlTest]] for url creation with "pretty" URL format.
*
* Behavior of UrlManager::parseRequest() for the "pretty" URL format varies among the following options:
* - strict parsing = true / false
* - rules format
* - key => value
* - array config
*
* The following features are tested:
* - named parameters
* - as query params
* - as controller/actions '<controller:(post|comment)>/<id:\d+>/<action:(update|delete)>' => '<controller>/<action>',
* - Rules with Server Names
* - with protocol
* - without protocol i.e protocol relative, see https://github.com/yiisoft/yii2/pull/12697
* - with parameters
* - with suffix
* - with default values
* - with HTTP methods
*
* - Adding rules dynamically
* - Test custom rules that only implement the interface
*
* NOTE: if a test is added here, you probably also need to add one in UrlManagerCreateUrlTest.
*
* @group web
*/
class UrlManagerParseUrlTest extends TestCase
{
protected function getUrlManager($config = [])
{
// in this test class, all tests have enablePrettyUrl enabled.
$config['enablePrettyUrl'] = true;
$config['cache'] = null;
// normalizer is tested in UrlNormalizerTest
$config['normalizer'] = false;
return new UrlManager($config);
}
protected function getRequest($pathInfo, $hostInfo = 'http://www.example.com', $method = 'GET', $config = [])
{
$config['pathInfo'] = $pathInfo;
$config['hostInfo'] = $hostInfo;
$_POST['_method'] = $method;
return new Request($config);
}
protected function tearDown()
{
unset($_POST['_method']);
parent::tearDown();
}
public function testWithoutRules()
{
$manager = $this->getUrlManager();
// empty pathinfo
$result = $manager->parseRequest($this->getRequest(''));
$this->assertEquals(['', []], $result);
// normal pathinfo
$result = $manager->parseRequest($this->getRequest('site/index'));
$this->assertEquals(['site/index', []], $result);
// pathinfo with module
$result = $manager->parseRequest($this->getRequest('module/site/index'));
$this->assertEquals(['module/site/index', []], $result);
// pathinfo with trailing slashes
$result = $manager->parseRequest($this->getRequest('module/site/index/'));
$this->assertEquals(['module/site/index/', []], $result);
}
public function testWithoutRulesStrict()
{
$manager = $this->getUrlManager();
$manager->enableStrictParsing = true;
// empty pathinfo
$this->assertFalse($manager->parseRequest($this->getRequest('')));
// normal pathinfo
$this->assertFalse($manager->parseRequest($this->getRequest('site/index')));
// pathinfo with module
$this->assertFalse($manager->parseRequest($this->getRequest('module/site/index')));
// pathinfo with trailing slashes
$this->assertFalse($manager->parseRequest($this->getRequest('module/site/index/')));
}
public function suffixProvider()
{
return [
['.html'],
['/'],
];
}
/**
* @dataProvider suffixProvider
*/
public function testWithoutRulesWithSuffix($suffix)
{
$manager = $this->getUrlManager(['suffix' => $suffix]);
// empty pathinfo
$result = $manager->parseRequest($this->getRequest(''));
$this->assertEquals(['', []], $result);
// normal pathinfo
$result = $manager->parseRequest($this->getRequest('site/index'));
$this->assertFalse($result);
$result = $manager->parseRequest($this->getRequest("site/index$suffix"));
$this->assertEquals(['site/index', []], $result);
// pathinfo with module
$result = $manager->parseRequest($this->getRequest('module/site/index'));
$this->assertFalse($result);
$result = $manager->parseRequest($this->getRequest("module/site/index$suffix"));
$this->assertEquals(['module/site/index', []], $result);
// pathinfo with trailing slashes
if ($suffix !== '/') {
$result = $manager->parseRequest($this->getRequest('module/site/index/'));
$this->assertFalse($result);
}
$result = $manager->parseRequest($this->getRequest("module/site/index/$suffix"));
$this->assertEquals(['module/site/index/', []], $result);
}
public function testSimpleRules()
{
$config = [
'rules' => [
'post/<id:\d+>' => 'post/view',
'posts' => 'post/index',
'book/<id:\d+>/<title>' => 'book/view',
],
];
$manager = $this->getUrlManager($config);
// matching pathinfo
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample'));
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
// trailing slash is significant, no match
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample/'));
$this->assertEquals(['book/123/this+is+sample/', []], $result);
// empty pathinfo
$result = $manager->parseRequest($this->getRequest(''));
$this->assertEquals(['', []], $result);
// normal pathinfo
$result = $manager->parseRequest($this->getRequest('site/index'));
$this->assertEquals(['site/index', []], $result);
// pathinfo with module
$result = $manager->parseRequest($this->getRequest('module/site/index'));
$this->assertEquals(['module/site/index', []], $result);
}
public function testSimpleRulesStrict()
{
$config = [
'rules' => [
'post/<id:\d+>' => 'post/view',
'posts' => 'post/index',
'book/<id:\d+>/<title>' => 'book/view',
],
];
$manager = $this->getUrlManager($config);
$manager->enableStrictParsing = true;
// matching pathinfo
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample'));
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
// trailing slash is significant, no match
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample/'));
$this->assertFalse($result);
// empty pathinfo
$result = $manager->parseRequest($this->getRequest(''));
$this->assertFalse($result);
// normal pathinfo
$result = $manager->parseRequest($this->getRequest('site/index'));
$this->assertFalse($result);
// pathinfo with module
$result = $manager->parseRequest($this->getRequest('module/site/index'));
$this->assertFalse($result);
}
/**
* @dataProvider suffixProvider
*/
public function testSimpleRulesWithSuffix($suffix)
{
$config = [
'rules' => [
'post/<id:\d+>' => 'post/view',
'posts' => 'post/index',
'book/<id:\d+>/<title>' => 'book/view',
],
'suffix' => $suffix,
];
$manager = $this->getUrlManager($config);
// matching pathinfo
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample"));
$this->assertFalse($result);
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample$suffix"));
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
// trailing slash is significant, no match
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample/"));
if ($suffix === '/') {
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
} else {
$this->assertFalse($result);
}
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample/$suffix"));
$this->assertEquals(['book/123/this+is+sample/', []], $result);
// empty pathinfo
$result = $manager->parseRequest($this->getRequest(''));
$this->assertEquals(['', []], $result);
// normal pathinfo
$result = $manager->parseRequest($this->getRequest("site/index"));
$this->assertFalse($result);
$result = $manager->parseRequest($this->getRequest("site/index$suffix"));
$this->assertEquals(['site/index', []], $result);
// pathinfo with module
$result = $manager->parseRequest($this->getRequest("module/site/index"));
$this->assertFalse($result);
$result = $manager->parseRequest($this->getRequest("module/site/index$suffix"));
$this->assertEquals(['module/site/index', []], $result);
}
/**
* @dataProvider suffixProvider
*/
public function testSimpleRulesWithSuffixStrict($suffix)
{
$config = [
'rules' => [
'post/<id:\d+>' => 'post/view',
'posts' => 'post/index',
'book/<id:\d+>/<title>' => 'book/view',
],
'suffix' => $suffix,
];
$manager = $this->getUrlManager($config);
$manager->enableStrictParsing = true;
// matching pathinfo
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample"));
$this->assertFalse($result);
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample$suffix"));
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
// trailing slash is significant, no match
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample/"));
if ($suffix === '/') {
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
} else {
$this->assertFalse($result);
}
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample/$suffix"));
$this->assertFalse($result);
// empty pathinfo
$result = $manager->parseRequest($this->getRequest(''));
$this->assertFalse($result);
// normal pathinfo
$result = $manager->parseRequest($this->getRequest("site/index"));
$this->assertFalse($result);
$result = $manager->parseRequest($this->getRequest("site/index$suffix"));
$this->assertFalse($result);
// pathinfo with module
$result = $manager->parseRequest($this->getRequest("module/site/index"));
$this->assertFalse($result);
$result = $manager->parseRequest($this->getRequest("module/site/index$suffix"));
$this->assertFalse($result);
}
// TODO implement with hostinfo
public function testParseRESTRequest()
{
$request = new Request;
// pretty URL rules
$manager = new UrlManager([
'enablePrettyUrl' => true,
'showScriptName' => false,
'cache' => null,
'rules' => [
'PUT,POST post/<id>/<title>' => 'post/create',
'DELETE post/<id>' => 'post/delete',
'post/<id>/<title>' => 'post/view',
'POST/GET' => 'post/get',
],
]);
// matching pathinfo GET request
$_SERVER['REQUEST_METHOD'] = 'GET';
$request->pathInfo = 'post/123/this+is+sample';
$result = $manager->parseRequest($request);
$this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
// matching pathinfo PUT/POST request
$_SERVER['REQUEST_METHOD'] = 'PUT';
$request->pathInfo = 'post/123/this+is+sample';
$result = $manager->parseRequest($request);
$this->assertEquals(['post/create', ['id' => '123', 'title' => 'this+is+sample']], $result);
$_SERVER['REQUEST_METHOD'] = 'POST';
$request->pathInfo = 'post/123/this+is+sample';
$result = $manager->parseRequest($request);
$this->assertEquals(['post/create', ['id' => '123', 'title' => 'this+is+sample']], $result);
// no wrong matching
$_SERVER['REQUEST_METHOD'] = 'POST';
$request->pathInfo = 'POST/GET';
$result = $manager->parseRequest($request);
$this->assertEquals(['post/get', []], $result);
// createUrl should ignore REST rules
$this->mockApplication([
'components' => [
'request' => [
'hostInfo' => 'http://localhost/',
'baseUrl' => '/app'
]
]
], \yii\web\Application::className());
$this->assertEquals('/app/post/delete?id=123', $manager->createUrl(['post/delete', 'id' => 123]));
$this->destroyApplication();
unset($_SERVER['REQUEST_METHOD']);
}
}