Security update for Core, with self-updated composer
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Path / PathValidatorTest.php
1 <?php
2
3 namespace Drupal\Tests\Core\Path;
4
5 use Drupal\Core\ParamConverter\ParamNotConvertedException;
6 use Drupal\Core\Path\PathValidator;
7 use Drupal\Tests\UnitTestCase;
8 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
9 use Symfony\Component\HttpFoundation\ParameterBag;
10 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
11 use Symfony\Component\Routing\Exception\MethodNotAllowedException;
12 use Symfony\Component\Routing\Exception\ResourceNotFoundException;
13
14 /**
15  * @coversDefaultClass \Drupal\Core\Path\PathValidator
16  * @group Routing
17  */
18 class PathValidatorTest extends UnitTestCase {
19
20   /**
21    * The mocked access aware router.
22    *
23    * @var \Drupal\Core\Routing\AccessAwareRouterInterface|\PHPUnit_Framework_MockObject_MockObject
24    */
25   protected $accessAwareRouter;
26
27   /**
28    * The mocked access unaware router.
29    * @var \Symfony\Component\Routing\Matcher\UrlMatcherInterface|\PHPUnit_Framework_MockObject_MockObject
30    */
31   protected $accessUnawareRouter;
32
33   /**
34    * The mocked account.
35    *
36    * @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject
37    */
38   protected $account;
39
40   /**
41    * The path processor.
42    *
43    * @var \Drupal\Core\PathProcessor\InboundPathProcessorInterface|\PHPUnit_Framework_MockObject_MockObject
44    */
45   protected $pathProcessor;
46
47   /**
48    * The tested path validator.
49    *
50    * @var \Drupal\Core\Path\PathValidator
51    */
52   protected $pathValidator;
53
54   /**
55    * {@inheritdoc}
56    */
57   protected function setUp() {
58     parent::setUp();
59
60     $this->accessAwareRouter = $this->getMock('Drupal\Core\Routing\AccessAwareRouterInterface');
61     $this->accessUnawareRouter = $this->getMock('Symfony\Component\Routing\Matcher\UrlMatcherInterface');
62     $this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
63     $this->pathProcessor = $this->getMock('Drupal\Core\PathProcessor\InboundPathProcessorInterface');
64     $this->pathValidator = new PathValidator($this->accessAwareRouter, $this->accessUnawareRouter, $this->account, $this->pathProcessor);
65   }
66
67   /**
68    * Tests the isValid() method for the frontpage.
69    *
70    * @covers ::isValid
71    */
72   public function testIsValidWithFrontpage() {
73     $this->accessAwareRouter->expects($this->never())
74       ->method('match');
75
76     $this->assertTrue($this->pathValidator->isValid('<front>'));
77   }
78
79   /**
80    * Tests the isValid() method for <none> (used for jumplinks).
81    *
82    * @covers ::isValid
83    */
84   public function testIsValidWithNone() {
85     $this->accessAwareRouter->expects($this->never())
86       ->method('match');
87
88     $this->assertTrue($this->pathValidator->isValid('<none>'));
89   }
90
91   /**
92    * Tests the isValid() method for an external URL.
93    *
94    * @covers ::isValid
95    */
96   public function testIsValidWithExternalUrl() {
97     $this->accessAwareRouter->expects($this->never())
98       ->method('match');
99
100     $this->assertTrue($this->pathValidator->isValid('https://www.drupal.org'));
101   }
102
103   /**
104    * Tests the isValid() method with an invalid external URL.
105    *
106    * @covers ::isValid
107    */
108   public function testIsValidWithInvalidExternalUrl() {
109     $this->accessAwareRouter->expects($this->never())
110       ->method('match');
111
112     $this->assertFalse($this->pathValidator->isValid('http://'));
113   }
114
115   /**
116    * Tests the isValid() method with a 'link to any page' permission.
117    *
118    * @covers ::isValid
119    * @covers ::getPathAttributes
120    */
121   public function testIsValidWithLinkToAnyPageAccount() {
122     $this->account->expects($this->once())
123       ->method('hasPermission')
124       ->with('link to any page')
125       ->willReturn(TRUE);
126     $this->accessAwareRouter->expects($this->never())
127       ->method('match');
128     $this->accessUnawareRouter->expects($this->once())
129       ->method('match')
130       ->with('/test-path')
131       ->willReturn([RouteObjectInterface::ROUTE_NAME => 'test_route', '_raw_variables' => new ParameterBag(['key' => 'value'])]);
132     $this->pathProcessor->expects($this->once())
133       ->method('processInbound')
134       ->willReturnArgument(0);
135
136     $this->assertTrue($this->pathValidator->isValid('test-path'));
137   }
138
139   /**
140    * Tests the isValid() method without the 'link to any page' permission.
141    *
142    * @covers ::isValid
143    */
144   public function testIsValidWithoutLinkToAnyPageAccount() {
145     $this->account->expects($this->once())
146       ->method('hasPermission')
147       ->with('link to any page')
148       ->willReturn(FALSE);
149     $this->accessUnawareRouter->expects($this->never())
150       ->method('match');
151     $this->accessAwareRouter->expects($this->once())
152       ->method('match')
153       ->with('/test-path')
154       ->willReturn([RouteObjectInterface::ROUTE_NAME => 'test_route', '_raw_variables' => new ParameterBag(['key' => 'value'])]);
155     $this->pathProcessor->expects($this->once())
156       ->method('processInbound')
157       ->willReturnArgument(0);
158
159     $this->assertTrue($this->pathValidator->isValid('test-path'));
160   }
161
162   /**
163    * Tests the isValid() method with a path alias.
164    *
165    * @covers ::isValid
166    */
167   public function testIsValidWithPathAlias() {
168     $this->account->expects($this->once())
169       ->method('hasPermission')
170       ->with('link to any page')
171       ->willReturn(FALSE);
172     $this->accessUnawareRouter->expects($this->never())
173       ->method('match');
174     $this->accessAwareRouter->expects($this->once())
175       ->method('match')
176       ->with('/test-path')
177       ->willReturn([RouteObjectInterface::ROUTE_NAME => 'test_route', '_raw_variables' => new ParameterBag(['key' => 'value'])]);
178     $this->pathProcessor->expects($this->once())
179       ->method('processInbound')
180       ->with('/path-alias', $this->anything())
181       ->willReturn('/test-path');
182
183     $this->assertTrue($this->pathValidator->isValid('path-alias'));
184   }
185
186   /**
187    * Tests the isValid() method with a user without access to the path.
188    *
189    * @covers ::isValid
190    * @covers ::getPathAttributes
191    */
192   public function testIsValidWithAccessDenied() {
193     $this->account->expects($this->once())
194       ->method('hasPermission')
195       ->with('link to any page')
196       ->willReturn(FALSE);
197     $this->accessUnawareRouter->expects($this->never())
198       ->method('match');
199     $this->accessAwareRouter->expects($this->once())
200       ->method('match')
201       ->with('/test-path')
202       ->willThrowException(new AccessDeniedHttpException());
203     $this->pathProcessor->expects($this->once())
204       ->method('processInbound')
205       ->willReturnArgument(0);
206
207     $this->assertFalse($this->pathValidator->isValid('test-path'));
208   }
209
210   /**
211    * @covers ::isValid
212    * @covers ::getPathAttributes
213    */
214   public function testIsValidWithResourceNotFound() {
215     $this->account->expects($this->once())
216       ->method('hasPermission')
217       ->with('link to any page')
218       ->willReturn(FALSE);
219     $this->accessUnawareRouter->expects($this->never())
220       ->method('match');
221     $this->accessAwareRouter->expects($this->once())
222       ->method('match')
223       ->with('/test-path')
224       ->willThrowException(new ResourceNotFoundException());
225     $this->pathProcessor->expects($this->once())
226       ->method('processInbound')
227       ->willReturnArgument(0);
228
229     $this->assertFalse($this->pathValidator->isValid('test-path'));
230   }
231
232   /**
233    * @covers ::isValid
234    * @covers ::getPathAttributes
235    */
236   public function testIsValidWithParamNotConverted() {
237     $this->account->expects($this->once())
238       ->method('hasPermission')
239       ->with('link to any page')
240       ->willReturn(FALSE);
241     $this->accessUnawareRouter->expects($this->never())
242       ->method('match');
243     $this->accessAwareRouter->expects($this->once())
244       ->method('match')
245       ->with('/test-path')
246       ->willThrowException(new ParamNotConvertedException());
247     $this->pathProcessor->expects($this->once())
248       ->method('processInbound')
249       ->willReturnArgument(0);
250
251     $this->assertFalse($this->pathValidator->isValid('test-path'));
252   }
253
254   /**
255    * @covers ::isValid
256    * @covers ::getPathAttributes
257    */
258   public function testIsValidWithMethodNotAllowed() {
259     $this->account->expects($this->once())
260       ->method('hasPermission')
261       ->with('link to any page')
262       ->willReturn(FALSE);
263     $this->accessUnawareRouter->expects($this->never())
264       ->method('match');
265     $this->accessAwareRouter->expects($this->once())
266       ->method('match')
267       ->with('/test-path')
268       ->willThrowException(new MethodNotAllowedException([]));
269     $this->pathProcessor->expects($this->once())
270       ->method('processInbound')
271       ->willReturnArgument(0);
272
273     $this->assertFalse($this->pathValidator->isValid('test-path'));
274   }
275
276   /**
277    * Tests the isValid() method with a not working param converting.
278    *
279    * @covers ::isValid
280    */
281   public function testIsValidWithFailingParameterConverting() {
282     $this->account->expects($this->once())
283       ->method('hasPermission')
284       ->with('link to any page')
285       ->willReturn(FALSE);
286     $this->accessUnawareRouter->expects($this->never())
287       ->method('match');
288     $this->accessAwareRouter->expects($this->once())
289       ->method('match')
290       ->with('/entity-test/1')
291       ->willThrowException(new ParamNotConvertedException());
292     $this->pathProcessor->expects($this->once())
293       ->method('processInbound')
294       ->willReturnArgument(0);
295
296     $this->assertFalse($this->pathValidator->isValid('entity-test/1'));
297   }
298
299   /**
300    * Tests the isValid() method with a not existing path.
301    *
302    * @covers ::isValid
303    */
304   public function testIsValidWithNotExistingPath() {
305     $this->account->expects($this->once())
306       ->method('hasPermission')
307       ->with('link to any page')
308       ->willReturn(FALSE);
309     $this->accessUnawareRouter->expects($this->never())
310       ->method('match');
311     $this->accessAwareRouter->expects($this->once())
312       ->method('match')
313       ->with('/not-existing-path')
314       ->willThrowException(new ResourceNotFoundException());
315     $this->pathProcessor->expects($this->once())
316       ->method('processInbound')
317       ->willReturnArgument(0);
318
319     $this->assertFalse($this->pathValidator->isValid('not-existing-path'));
320   }
321
322   /**
323    * Tests the getUrlIfValid() method when there is access.
324    *
325    * @covers ::getUrlIfValid
326    * @covers ::getPathAttributes
327    */
328   public function testGetUrlIfValidWithAccess() {
329     $this->account->expects($this->exactly(2))
330       ->method('hasPermission')
331       ->with('link to any page')
332       ->willReturn(FALSE);
333
334     $this->accessAwareRouter->expects($this->exactly(2))
335       ->method('match')
336       ->with('/test-path')
337       ->willReturn([RouteObjectInterface::ROUTE_NAME => 'test_route', '_raw_variables' => new ParameterBag(['key' => 'value'])]);
338     $this->pathProcessor->expects($this->exactly(2))
339       ->method('processInbound')
340       ->willReturnArgument(0);
341
342     $url = $this->pathValidator->getUrlIfValid('test-path');
343     $this->assertInstanceOf('Drupal\Core\Url', $url);
344
345     $this->assertEquals('test_route', $url->getRouteName());
346     $this->assertEquals(['key' => 'value'], $url->getRouteParameters());
347
348     // Test with leading /.
349     $url = $this->pathValidator->getUrlIfValid('/test-path');
350     $this->assertInstanceOf('Drupal\Core\Url', $url);
351
352     $this->assertEquals('test_route', $url->getRouteName());
353     $this->assertEquals(['key' => 'value'], $url->getRouteParameters());
354   }
355
356   /**
357    * Tests the getUrlIfValid() method with a query in the path.
358    *
359    * @covers ::getUrlIfValid
360    */
361   public function testGetUrlIfValidWithQuery() {
362     $this->account->expects($this->once())
363       ->method('hasPermission')
364       ->with('link to any page')
365       ->willReturn(FALSE);
366
367     $this->accessAwareRouter->expects($this->once())
368       ->method('match')
369       ->with('/test-path?k=bar')
370       ->willReturn([RouteObjectInterface::ROUTE_NAME => 'test_route', '_raw_variables' => new ParameterBag()]);
371     $this->pathProcessor->expects($this->once())
372       ->method('processInbound')
373       ->willReturnArgument(0);
374
375     $url = $this->pathValidator->getUrlIfValid('test-path?k=bar');
376     $this->assertInstanceOf('Drupal\Core\Url', $url);
377
378     $this->assertEquals('test_route', $url->getRouteName());
379     $this->assertEquals(['k' => 'bar'], $url->getOptions()['query']);
380   }
381
382   /**
383    * Tests the getUrlIfValid() method where there is no access.
384    *
385    * @covers ::getUrlIfValid
386    */
387   public function testGetUrlIfValidWithoutAccess() {
388     $this->account->expects($this->once())
389       ->method('hasPermission')
390       ->with('link to any page')
391       ->willReturn(FALSE);
392
393     $this->accessAwareRouter->expects($this->once())
394       ->method('match')
395       ->with('/test-path')
396       ->willThrowException(new AccessDeniedHttpException());
397
398     $this->pathProcessor->expects($this->once())
399       ->method('processInbound')
400       ->willReturnArgument(0);
401
402     $url = $this->pathValidator->getUrlIfValid('test-path');
403     $this->assertFalse($url);
404   }
405
406   /**
407    * Tests the getUrlIfValid() method with a front page + query + fragments.
408    *
409    * @covers ::getUrlIfValid
410    */
411   public function testGetUrlIfValidWithFrontPageAndQueryAndFragments() {
412     $url = $this->pathValidator->getUrlIfValid('<front>?hei=sen#berg');
413     $this->assertEquals('<front>', $url->getRouteName());
414     $this->assertEquals(['hei' => 'sen'], $url->getOptions()['query']);
415     $this->assertEquals('berg', $url->getOptions()['fragment']);
416   }
417
418   /**
419    * Tests the getUrlIfValidWithoutAccessCheck() method.
420    *
421    * @covers ::getUrlIfValidWithoutAccessCheck
422    * @covers ::getPathAttributes
423    */
424   public function testGetUrlIfValidWithoutAccessCheck() {
425     $this->account->expects($this->never())
426       ->method('hasPermission')
427       ->with('link to any page');
428     $this->accessAwareRouter->expects($this->never())
429       ->method('match');
430     $this->accessUnawareRouter->expects($this->once())
431       ->method('match')
432       ->with('/test-path')
433       ->willReturn([RouteObjectInterface::ROUTE_NAME => 'test_route', '_raw_variables' => new ParameterBag(['key' => 'value'])]);
434     $this->pathProcessor->expects($this->once())
435       ->method('processInbound')
436       ->willReturnArgument(0);
437
438     $url = $this->pathValidator->getUrlIfValidWithoutAccessCheck('test-path');
439     $this->assertInstanceOf('Drupal\Core\Url', $url);
440
441     $this->assertEquals('test_route', $url->getRouteName());
442     $this->assertEquals(['key' => 'value'], $url->getRouteParameters());
443   }
444
445 }