Completed
Push — master ( 29f099...87ed20 )
by Łukasz
24:25
created

DefaultRouterTest::generateRouter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the DefaultRouterTest class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Bundle\EzPublishCoreBundle\Tests\Routing;
10
11
use eZ\Bundle\EzPublishCoreBundle\Routing\DefaultRouter;
12
use eZ\Bundle\EzPublishCoreBundle\SiteAccess\Matcher;
13
use eZ\Publish\Core\MVC\ConfigResolverInterface;
14
use eZ\Publish\Core\MVC\Symfony\Routing\SimplifiedRequest;
15
use eZ\Publish\Core\MVC\Symfony\SiteAccess;
16
use Symfony\Component\DependencyInjection\ContainerInterface;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\Routing\RequestContext;
19
use ReflectionObject;
20
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
21
use PHPUnit\Framework\TestCase;
22
23
class DefaultRouterTest extends TestCase
24
{
25
    /**
26
     * @var \PHPUnit\Framework\MockObject\MockObject|\Symfony\Component\DependencyInjection\ContainerInterface
27
     */
28
    protected $container;
29
30
    /**
31
     * @var \PHPUnit\Framework\MockObject\MockObject|\eZ\Publish\Core\MVC\ConfigResolverInterface
32
     */
33
    protected $configResolver;
34
35
    /**
36
     * @var \Symfony\Component\Routing\RequestContext
37
     */
38
    protected $requestContext;
39
40
    protected function setUp()
41
    {
42
        parent::setUp();
43
        $this->container = $this->createMock(ContainerInterface::class);
44
        $this->configResolver = $this->createMock(ConfigResolverInterface::class);
45
        $this->requestContext = new RequestContext();
46
    }
47
48
    protected function getRouterClass()
49
    {
50
        return DefaultRouter::class;
51
    }
52
53
    /**
54
     * @param array $mockedMethods
55
     *
56
     * @return \PHPUnit\Framework\MockObject\MockObject|DefaultRouter
57
     */
58
    protected function generateRouter(array $mockedMethods = array())
59
    {
60
        /** @var \PHPUnit\Framework\MockObject\MockObject|DefaultRouter $router */
61
        $router = $this
62
            ->getMockBuilder($this->getRouterClass())
63
            ->setConstructorArgs(array($this->container, 'foo', array(), $this->requestContext))
64
            ->setMethods(array_merge($mockedMethods))
65
            ->getMock();
66
        $router->setConfigResolver($this->configResolver);
0 ignored issues
show
Bug introduced by
It seems like $this->configResolver can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, eZ\Bundle\EzPublishCoreB...er::setConfigResolver() does only seem to accept object<eZ\Publish\Core\M...onfigResolverInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
67
68
        return $router;
69
    }
70
71
    public function testMatchRequestWithSemanticPathinfo()
72
    {
73
        $pathinfo = '/siteaccess/foo/bar';
74
        $semanticPathinfo = '/foo/bar';
75
        $request = Request::create($pathinfo);
76
        $request->attributes->set('semanticPathinfo', $semanticPathinfo);
77
78
        /** @var \PHPUnit\Framework\MockObject\MockObject|DefaultRouter $router */
79
        $router = $this->generateRouter(array('match'));
80
81
        $matchedParameters = array('_controller' => 'AcmeBundle:myAction');
82
        $router
83
            ->expects($this->once())
84
            ->method('match')
85
            ->with($semanticPathinfo)
86
            ->will($this->returnValue($matchedParameters));
87
        $this->assertSame($matchedParameters, $router->matchRequest($request));
88
    }
89
90
    public function testMatchRequestRegularPathinfo()
91
    {
92
        $matchedParameters = array('_controller' => 'AcmeBundle:myAction');
93
        $pathinfo = '/siteaccess/foo/bar';
94
95
        $request = Request::create($pathinfo);
96
97
        $this->configResolver->expects($this->never())->method('getParameter');
98
99
        /** @var \PHPUnit\Framework\MockObject\MockObject|DefaultRouter $router */
100
        $router = $this->generateRouter(array('match'));
101
        $router
102
            ->expects($this->once())
103
            ->method('match')
104
            ->with($pathinfo)
105
            ->will($this->returnValue($matchedParameters));
106
        $this->assertSame($matchedParameters, $router->matchRequest($request));
107
    }
108
109
    /**
110
     * @dataProvider providerGenerateNoSiteAccess
111
     */
112
    public function testGenerateNoSiteAccess($url)
113
    {
114
        $generator = $this->createMock(UrlGeneratorInterface::class);
115
        $generator
116
            ->expects($this->once())
117
            ->method('generate')
118
            ->with(__METHOD__)
119
            ->will($this->returnValue($url));
120
121
        /** @var DefaultRouter|\PHPUnit\Framework\MockObject\MockObject $router */
122
        $router = $this->generateRouter(array('getGenerator'));
123
        $router
124
            ->expects($this->any())
125
            ->method('getGenerator')
126
            ->will($this->returnValue($generator));
127
128
        $this->assertSame($url, $router->generate(__METHOD__));
129
    }
130
131 View Code Duplication
    public function providerGenerateNoSiteAccess()
132
    {
133
        return array(
134
            array('/foo/bar'),
135
            array('/foo/bar/baz?truc=muche&tata=toto'),
136
            array('http://ez.no/Products/eZ-Publish-CMS'),
137
            array('http://www.metalfrance.net/decouvertes/edge-caress-inverse-ep'),
138
        );
139
    }
140
141
    /**
142
     * @dataProvider providerGenerateWithSiteAccess
143
     *
144
     * @param string $urlGenerated The URL generated by the standard UrLGenerator
145
     * @param string $relevantUri The relevant URI part of the generated URL (without host and basepath)
146
     * @param string $expectedUrl The URL we're expecting to be finally generated, with siteaccess
147
     * @param string $saName The SiteAccess name
148
     * @param bool $isMatcherLexer True if the siteaccess matcher is URILexer
149
     * @param int $referenceType The type of reference to be generated (one of the constants)
150
     * @param string $routeName
151
     */
152
    public function testGenerateWithSiteAccess($urlGenerated, $relevantUri, $expectedUrl, $saName, $isMatcherLexer, $referenceType, $routeName)
153
    {
154
        $routeName = $routeName ?: __METHOD__;
155
        $nonSiteAccessAwareRoutes = array('_dontwantsiteaccess');
156
        $generator = $this->createMock(UrlGeneratorInterface::class);
157
        $generator
158
            ->expects($this->once())
159
            ->method('generate')
160
            ->with($routeName)
161
            ->will($this->returnValue($urlGenerated));
162
163
        /** @var DefaultRouter|\PHPUnit\Framework\MockObject\MockObject $router */
164
        $router = $this->generateRouter(array('getGenerator'));
165
        $router
166
            ->expects($this->any())
167
            ->method('getGenerator')
168
            ->will($this->returnValue($generator));
169
170
        // If matcher is URILexer, we make it act as it's supposed to, prepending the siteaccess.
171
        if ($isMatcherLexer) {
172
            $matcher = $this->createMock(SiteAccess\URILexer::class);
173
            // Route is siteaccess aware, we're expecting analyseLink() to be called
174
            if (!in_array($routeName, $nonSiteAccessAwareRoutes)) {
175
                $matcher
176
                    ->expects($this->once())
177
                    ->method('analyseLink')
178
                    ->with($relevantUri)
179
                    ->will($this->returnValue("/$saName$relevantUri"));
180
            } else {
181
                // Non-siteaccess aware route, it's not supposed to be analysed
182
                $matcher
183
                    ->expects($this->never())
184
                    ->method('analyseLink');
185
            }
186
        } else {
187
            $matcher = $this->createMock(Matcher::class);
188
        }
189
190
        $sa = new SiteAccess($saName, 'test', $matcher);
191
        $router->setSiteAccess($sa);
192
193
        $requestContext = new RequestContext();
194
        $urlComponents = parse_url($urlGenerated);
195 View Code Duplication
        if (isset($urlComponents['host'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
196
            $requestContext->setHost($urlComponents['host']);
197
            $requestContext->setScheme($urlComponents['scheme']);
198
            if (isset($urlComponents['port']) && $urlComponents['scheme'] === 'http') {
199
                $requestContext->setHttpPort($urlComponents['port']);
200
            } elseif (isset($urlComponents['port']) && $urlComponents['scheme'] === 'https') {
201
                $requestContext->setHttpsPort($urlComponents['port']);
202
            }
203
        }
204
        $requestContext->setBaseUrl(
205
            substr($urlComponents['path'], 0, strpos($urlComponents['path'], $relevantUri))
206
        );
207
        $router->setContext($requestContext);
208
        $router->setNonSiteAccessAwareRoutes($nonSiteAccessAwareRoutes);
209
210
        $this->assertSame($expectedUrl, $router->generate($routeName, array(), $referenceType));
211
    }
212
213
    public function providerGenerateWithSiteAccess()
214
    {
215
        return array(
216
            array('/foo/bar', '/foo/bar', '/foo/bar', 'test_siteaccess', false, UrlGeneratorInterface::ABSOLUTE_PATH, null),
217
            array('http://ezpublish.dev/foo/bar', '/foo/bar', 'http://ezpublish.dev/foo/bar', 'test_siteaccess', false, UrlGeneratorInterface::ABSOLUTE_URL, null),
218
            array('http://ezpublish.dev/foo/bar', '/foo/bar', 'http://ezpublish.dev/test_siteaccess/foo/bar', 'test_siteaccess', true, UrlGeneratorInterface::ABSOLUTE_URL, null),
219
            array('http://ezpublish.dev/foo/bar', '/foo/bar', 'http://ezpublish.dev/foo/bar', 'test_siteaccess', true, UrlGeneratorInterface::ABSOLUTE_URL, '_dontwantsiteaccess'),
220
            array('http://ezpublish.dev:8080/foo/bar', '/foo/bar', 'http://ezpublish.dev:8080/test_siteaccess/foo/bar', 'test_siteaccess', true, UrlGeneratorInterface::ABSOLUTE_URL, null),
221
            array('http://ezpublish.dev:8080/foo/bar', '/foo/bar', 'http://ezpublish.dev:8080/foo/bar', 'test_siteaccess', true, UrlGeneratorInterface::ABSOLUTE_URL, '_dontwantsiteaccess'),
222
            array('https://ezpublish.dev/secured', '/secured', 'https://ezpublish.dev/test_siteaccess/secured', 'test_siteaccess', true, UrlGeneratorInterface::ABSOLUTE_URL, null),
223
            array('https://ezpublish.dev:445/secured', '/secured', 'https://ezpublish.dev:445/test_siteaccess/secured', 'test_siteaccess', true, UrlGeneratorInterface::ABSOLUTE_URL, null),
224
            array('http://ezpublish.dev:8080/foo/root_folder/bar/baz', '/bar/baz', 'http://ezpublish.dev:8080/foo/root_folder/test_siteaccess/bar/baz', 'test_siteaccess', true, UrlGeneratorInterface::ABSOLUTE_URL, null),
225
            array('/foo/bar/baz', '/foo/bar/baz', '/test_siteaccess/foo/bar/baz', 'test_siteaccess', true, UrlGeneratorInterface::ABSOLUTE_PATH, null),
226
            array('/foo/root_folder/bar/baz', '/bar/baz', '/foo/root_folder/test_siteaccess/bar/baz', 'test_siteaccess', true, UrlGeneratorInterface::ABSOLUTE_PATH, null),
227
            array('/foo/bar/baz', '/foo/bar/baz', '/foo/bar/baz', 'test_siteaccess', true, UrlGeneratorInterface::ABSOLUTE_PATH, '_dontwantsiteaccess'),
228
        );
229
    }
230
231
    public function testGenerateReverseSiteAccessMatch()
232
    {
233
        $routeName = 'some_route_name';
234
        $urlGenerated = 'http://phoenix-rises.fm/foo/bar';
235
236
        $siteAccessName = 'foo_test';
237
        $siteAccessRouter = $this->createMock(SiteAccess\SiteAccessRouterInterface::class);
238
        $versatileMatcher = $this->createMock(SiteAccess\VersatileMatcher::class);
239
        $simplifiedRequest = new SimplifiedRequest(
240
            array(
241
                'host' => 'phoenix-rises.fm',
242
                'scheme' => 'http',
243
            )
244
        );
245
        $versatileMatcher
246
            ->expects($this->once())
247
            ->method('getRequest')
248
            ->will($this->returnValue($simplifiedRequest));
249
        $siteAccessRouter
250
            ->expects($this->once())
251
            ->method('matchByName')
252
            ->with($siteAccessName)
253
            ->will($this->returnValue(new SiteAccess($siteAccessName, 'foo', $versatileMatcher)));
254
255
        $generator = $this->createMock(UrlGeneratorInterface::class);
256
        $generator
257
            ->expects($this->at(0))
258
            ->method('setContext')
259
            ->with($this->isInstanceOf(RequestContext::class));
260
        $generator
261
            ->expects($this->at(1))
262
            ->method('generate')
263
            ->with($routeName)
264
            ->will($this->returnValue($urlGenerated));
265
        $generator
266
            ->expects($this->at(2))
267
            ->method('setContext')
268
            ->with($this->requestContext);
269
270
        $router = new DefaultRouter($this->container, 'foo', array(), $this->requestContext);
0 ignored issues
show
Bug introduced by
It seems like $this->container can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, Symfony\Bundle\Framework...g\Router::__construct() does only seem to accept object<Symfony\Component...ion\ContainerInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
271
        $router->setConfigResolver($this->configResolver);
0 ignored issues
show
Bug introduced by
It seems like $this->configResolver can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, eZ\Bundle\EzPublishCoreB...er::setConfigResolver() does only seem to accept object<eZ\Publish\Core\M...onfigResolverInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
272
        $router->setSiteAccess(new SiteAccess('test', 'test', $this->createMock(Matcher::class)));
273
        $router->setSiteAccessRouter($siteAccessRouter);
274
        $refRouter = new ReflectionObject($router);
275
        $refGenerator = $refRouter->getProperty('generator');
276
        $refGenerator->setAccessible(true);
277
        $refGenerator->setValue($router, $generator);
278
279
        $this->assertSame(
280
            $urlGenerated,
281
            $router->generate($routeName, array('siteaccess' => $siteAccessName), DefaultRouter::ABSOLUTE_PATH)
282
        );
283
    }
284
285
    /**
286
     * @dataProvider providerGetContextBySimplifiedRequest
287
     *
288
     * @param string $uri
289
     */
290
    public function testGetContextBySimplifiedRequest($uri)
291
    {
292
        $this->getExpectedRequestContext($uri);
293
294
        $router = new DefaultRouter($this->container, 'foo', [], $this->requestContext);
0 ignored issues
show
Bug introduced by
It seems like $this->container can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, Symfony\Bundle\Framework...g\Router::__construct() does only seem to accept object<Symfony\Component...ion\ContainerInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
295
296
        self::assertEquals(
297
            $this->getExpectedRequestContext($uri),
298
            $router->getContextBySimplifiedRequest(SimplifiedRequest::fromUrl($uri))
299
        );
300
    }
301
302
    /**
303
     * Data provider for testGetContextBySimplifiedRequest.
304
     *
305
     * @see testGetContextBySimplifiedRequest
306
     *
307
     * @return array
308
     */
309 View Code Duplication
    public function providerGetContextBySimplifiedRequest()
310
    {
311
        return [
312
            ['/foo/bar'],
313
            ['http://ezpublish.dev/foo/bar'],
314
            ['http://ezpublish.dev:8080/foo/bar'],
315
            ['https://ezpublish.dev/secured'],
316
            ['https://ezpublish.dev:445/secured'],
317
            ['http://ezpublish.dev:8080/foo/root_folder/bar/baz'],
318
        ];
319
    }
320
321
    private function getExpectedRequestContext($uri)
322
    {
323
        $requestContext = new RequestContext();
324
        $uriComponents = parse_url($uri);
325 View Code Duplication
        if (isset($uriComponents['host'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
326
            $requestContext->setHost($uriComponents['host']);
327
            $requestContext->setScheme($uriComponents['scheme']);
328
            if (isset($uriComponents['port']) && $uriComponents['scheme'] === 'http') {
329
                $requestContext->setHttpPort($uriComponents['port']);
330
            } elseif (isset($uriComponents['port']) && $uriComponents['scheme'] === 'https') {
331
                $requestContext->setHttpsPort($uriComponents['port']);
332
            }
333
        }
334
        if (isset($uriComponents['path'])) {
335
            $requestContext->setPathInfo($uriComponents['path']);
336
        }
337
338
        return $requestContext;
339
    }
340
}
341