Chris@0: '1'], [], FALSE, '/node/1']; Chris@0: $map[] = ['node_edit', ['node' => '2'], [], FALSE, '/node/2/edit']; Chris@0: $this->map = $map; Chris@0: Chris@0: $alias_map = [ Chris@0: // Set up one proper alias that can be resolved to a system path. Chris@0: ['node-alias-test', NULL, FALSE, 'node'], Chris@0: // Passing in anything else should return the same string. Chris@0: ['node', NULL, FALSE, 'node'], Chris@0: ['node/1', NULL, FALSE, 'node/1'], Chris@0: ['node/2/edit', NULL, FALSE, 'node/2/edit'], Chris@0: ['non-existent', NULL, FALSE, 'non-existent'], Chris@0: ]; Chris@0: Chris@0: // $this->map has $collect_bubbleable_metadata = FALSE; also generate the Chris@0: // $collect_bubbleable_metadata = TRUE case for ::generateFromRoute(). Chris@0: $generate_from_route_map = []; Chris@0: foreach ($this->map as $values) { Chris@0: $generate_from_route_map[] = $values; Chris@0: $generate_from_route_map[] = [$values[0], $values[1], $values[2], TRUE, (new GeneratedUrl())->setGeneratedUrl($values[4])]; Chris@0: } Chris@0: $this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface'); Chris@0: $this->urlGenerator->expects($this->any()) Chris@0: ->method('generateFromRoute') Chris@0: ->will($this->returnValueMap($generate_from_route_map)); Chris@0: Chris@0: $this->pathAliasManager = $this->getMock('Drupal\Core\Path\AliasManagerInterface'); Chris@0: $this->pathAliasManager->expects($this->any()) Chris@0: ->method('getPathByAlias') Chris@0: ->will($this->returnValueMap($alias_map)); Chris@0: Chris@0: $this->router = $this->getMock('Drupal\Tests\Core\Routing\TestRouterInterface'); Chris@0: $this->pathValidator = $this->getMock('Drupal\Core\Path\PathValidatorInterface'); Chris@0: Chris@0: $this->container = new ContainerBuilder(); Chris@0: $this->container->set('router.no_access_checks', $this->router); Chris@0: $this->container->set('url_generator', $this->urlGenerator); Chris@0: $this->container->set('path.alias_manager', $this->pathAliasManager); Chris@0: $this->container->set('path.validator', $this->pathValidator); Chris@0: \Drupal::setContainer($this->container); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests creating a Url from a request. Chris@0: */ Chris@0: public function testUrlFromRequest() { Chris@0: $this->router->expects($this->at(0)) Chris@0: ->method('matchRequest') Chris@0: ->with($this->getRequestConstraint('/node')) Chris@0: ->willReturn([ Chris@0: RouteObjectInterface::ROUTE_NAME => 'view.frontpage.page_1', Chris@0: '_raw_variables' => new ParameterBag(), Chris@0: ]); Chris@0: $this->router->expects($this->at(1)) Chris@0: ->method('matchRequest') Chris@0: ->with($this->getRequestConstraint('/node/1')) Chris@0: ->willReturn([ Chris@0: RouteObjectInterface::ROUTE_NAME => 'node_view', Chris@0: '_raw_variables' => new ParameterBag(['node' => '1']), Chris@0: ]); Chris@0: $this->router->expects($this->at(2)) Chris@0: ->method('matchRequest') Chris@0: ->with($this->getRequestConstraint('/node/2/edit')) Chris@0: ->willReturn([ Chris@0: RouteObjectInterface::ROUTE_NAME => 'node_edit', Chris@0: '_raw_variables' => new ParameterBag(['node' => '2']), Chris@0: ]); Chris@0: Chris@0: $urls = []; Chris@0: foreach ($this->map as $index => $values) { Chris@0: $path = array_pop($values); Chris@0: $url = Url::createFromRequest(Request::create("$path")); Chris@0: $expected = Url::fromRoute($values[0], $values[1], $values[2]); Chris@0: $this->assertEquals($expected, $url); Chris@0: $urls[$index] = $url; Chris@0: } Chris@0: return $urls; Chris@0: } Chris@0: Chris@0: /** Chris@0: * This constraint checks whether a Request object has the right path. Chris@0: * Chris@0: * @param string $path Chris@0: * The path. Chris@0: * Chris@0: * @return \PHPUnit_Framework_Constraint_Callback Chris@0: * The constraint checks whether a Request object has the right path. Chris@0: */ Chris@0: protected function getRequestConstraint($path) { Chris@0: return $this->callback(function (Request $request) use ($path) { Chris@0: return $request->getPathInfo() == $path; Chris@0: }); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the fromRoute() method with the special path. Chris@0: * Chris@0: * @covers ::fromRoute Chris@0: */ Chris@0: public function testFromRouteFront() { Chris@0: $url = Url::fromRoute(''); Chris@0: $this->assertSame('', $url->getRouteName()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the fromUserInput method with valid paths. Chris@0: * Chris@0: * @covers ::fromUserInput Chris@0: * @dataProvider providerFromValidInternalUri Chris@0: */ Chris@0: public function testFromUserInput($path) { Chris@0: $url = Url::fromUserInput($path); Chris@0: $uri = $url->getUri(); Chris@0: Chris@0: $this->assertInstanceOf('Drupal\Core\Url', $url); Chris@0: $this->assertFalse($url->isRouted()); Chris@0: $this->assertEquals(0, strpos($uri, 'base:')); Chris@0: Chris@0: $parts = UrlHelper::parse($path); Chris@0: $options = $url->getOptions(); Chris@0: Chris@0: if (!empty($parts['fragment'])) { Chris@0: $this->assertSame($parts['fragment'], $options['fragment']); Chris@0: } Chris@0: else { Chris@0: $this->assertArrayNotHasKey('fragment', $options); Chris@0: } Chris@0: Chris@0: if (!empty($parts['query'])) { Chris@0: $this->assertEquals($parts['query'], $options['query']); Chris@0: } Chris@0: else { Chris@0: $this->assertArrayNotHasKey('query', $options); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the fromUserInput method with invalid paths. Chris@0: * Chris@0: * @covers ::fromUserInput Chris@0: * @dataProvider providerFromInvalidInternalUri Chris@0: */ Chris@0: public function testFromInvalidUserInput($path) { Chris@0: $this->setExpectedException(\InvalidArgumentException::class); Chris@0: $url = Url::fromUserInput($path); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests fromUri() method with a user-entered path not matching any route. Chris@0: * Chris@0: * @covers ::fromUri Chris@0: */ Chris@0: public function testFromRoutedPathWithInvalidRoute() { Chris@0: $this->pathValidator->expects($this->once()) Chris@0: ->method('getUrlIfValidWithoutAccessCheck') Chris@0: ->with('invalid-path') Chris@0: ->willReturn(FALSE); Chris@0: $url = Url::fromUri('internal:/invalid-path'); Chris@0: $this->assertSame(FALSE, $url->isRouted()); Chris@0: $this->assertSame('base:invalid-path', $url->getUri()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests fromUri() method with user-entered path matching a valid route. Chris@0: * Chris@0: * @covers ::fromUri Chris@0: */ Chris@0: public function testFromRoutedPathWithValidRoute() { Chris@0: $url = Url::fromRoute('test_route'); Chris@0: $this->pathValidator->expects($this->once()) Chris@0: ->method('getUrlIfValidWithoutAccessCheck') Chris@0: ->with('valid-path') Chris@0: ->willReturn($url); Chris@0: $result_url = Url::fromUri('internal:/valid-path'); Chris@0: $this->assertSame($url, $result_url); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the createFromRequest method. Chris@0: * Chris@0: * @covers ::createFromRequest Chris@0: */ Chris@0: public function testCreateFromRequest() { Chris@0: $attributes = [ Chris@0: '_raw_variables' => new ParameterBag([ Chris@0: 'color' => 'chartreuse', Chris@0: ]), Chris@0: RouteObjectInterface::ROUTE_NAME => 'the_route_name', Chris@0: ]; Chris@0: $request = new Request([], [], $attributes); Chris@0: Chris@0: $this->router->expects($this->once()) Chris@0: ->method('matchRequest') Chris@0: ->with($request) Chris@0: ->will($this->returnValue($attributes)); Chris@0: Chris@0: $url = Url::createFromRequest($request); Chris@0: $expected = new Url('the_route_name', ['color' => 'chartreuse']); Chris@0: $this->assertEquals($expected, $url); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that an invalid request will thrown an exception. Chris@0: * Chris@0: * @covers ::createFromRequest Chris@0: */ Chris@0: public function testUrlFromRequestInvalid() { Chris@0: $request = Request::create('/test-path'); Chris@0: Chris@0: $this->router->expects($this->once()) Chris@0: ->method('matchRequest') Chris@0: ->with($request) Chris@0: ->will($this->throwException(new ResourceNotFoundException())); Chris@0: Chris@0: $this->setExpectedException(ResourceNotFoundException::class); Chris@0: Url::createFromRequest($request); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the isExternal() method. Chris@0: * Chris@0: * @depends testUrlFromRequest Chris@0: * Chris@0: * @covers ::isExternal Chris@0: */ Chris@0: public function testIsExternal($urls) { Chris@0: foreach ($urls as $url) { Chris@0: $this->assertFalse($url->isExternal()); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the getUri() method for internal URLs. Chris@0: * Chris@0: * @param \Drupal\Core\Url[] $urls Chris@0: * Array of URL objects. Chris@0: * Chris@0: * @depends testUrlFromRequest Chris@0: * Chris@0: * @covers ::getUri Chris@0: */ Chris@0: public function testGetUriForInternalUrl($urls) { Chris@0: $this->setExpectedException(\UnexpectedValueException::class); Chris@0: foreach ($urls as $url) { Chris@0: $url->getUri(); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the getUri() method for external URLs. Chris@0: * Chris@0: * @covers ::getUri Chris@0: */ Chris@0: public function testGetUriForExternalUrl() { Chris@0: $url = Url::fromUri('http://example.com/test'); Chris@0: $this->assertEquals('http://example.com/test', $url->getUri()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the getUri() and isExternal() methods for protocol-relative URLs. Chris@0: * Chris@0: * @covers ::getUri Chris@0: * @covers ::isExternal Chris@0: */ Chris@0: public function testGetUriForProtocolRelativeUrl() { Chris@0: $url = Url::fromUri('//example.com/test'); Chris@0: $this->assertEquals('//example.com/test', $url->getUri()); Chris@0: $this->assertTrue($url->isExternal()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the getInternalPath method(). Chris@0: * Chris@0: * @param \Drupal\Core\Url[] $urls Chris@0: * Array of URL objects. Chris@0: * Chris@0: * @covers ::getInternalPath Chris@0: * Chris@0: * @depends testUrlFromRequest Chris@0: */ Chris@0: public function testGetInternalPath($urls) { Chris@0: $map = []; Chris@0: $map[] = ['view.frontpage.page_1', [], '/node']; Chris@0: $map[] = ['node_view', ['node' => '1'], '/node/1']; Chris@0: $map[] = ['node_edit', ['node' => '2'], '/node/2/edit']; Chris@0: Chris@0: foreach ($urls as $index => $url) { Chris@0: // Clone the url so that there is no leak of internal state into the Chris@0: // other ones. Chris@0: $url = clone $url; Chris@0: $url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface'); Chris@0: $url_generator->expects($this->once()) Chris@0: ->method('getPathFromRoute') Chris@0: ->will($this->returnValueMap($map, $index)); Chris@0: $url->setUrlGenerator($url_generator); Chris@0: Chris@0: $url->getInternalPath(); Chris@0: $url->getInternalPath(); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the toString() method. Chris@0: * Chris@0: * @param \Drupal\Core\Url[] $urls Chris@0: * An array of Url objects. Chris@0: * Chris@0: * @depends testUrlFromRequest Chris@0: * Chris@0: * @covers ::toString Chris@0: */ Chris@0: public function testToString($urls) { Chris@0: foreach ($urls as $index => $url) { Chris@0: $path = array_pop($this->map[$index]); Chris@0: $this->assertSame($path, $url->toString()); Chris@0: $generated_url = $url->toString(TRUE); Chris@0: $this->assertSame($path, $generated_url->getGeneratedUrl()); Chris@0: $this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_url); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the getRouteName() method. Chris@0: * Chris@0: * @param \Drupal\Core\Url[] $urls Chris@0: * An array of Url objects. Chris@0: * Chris@0: * @depends testUrlFromRequest Chris@0: * Chris@0: * @covers ::getRouteName Chris@0: */ Chris@0: public function testGetRouteName($urls) { Chris@0: foreach ($urls as $index => $url) { Chris@0: $this->assertSame($this->map[$index][0], $url->getRouteName()); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the getRouteName() with an external URL. Chris@0: * Chris@0: * @covers ::getRouteName Chris@0: */ Chris@0: public function testGetRouteNameWithExternalUrl() { Chris@0: $url = Url::fromUri('http://example.com'); Chris@0: $this->setExpectedException(\UnexpectedValueException::class); Chris@0: $url->getRouteName(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the getRouteParameters() method. Chris@0: * Chris@0: * @param \Drupal\Core\Url[] $urls Chris@0: * An array of Url objects. Chris@0: * Chris@0: * @depends testUrlFromRequest Chris@0: * Chris@0: * @covers ::getRouteParameters Chris@0: */ Chris@0: public function testGetRouteParameters($urls) { Chris@0: foreach ($urls as $index => $url) { Chris@0: $this->assertSame($this->map[$index][1], $url->getRouteParameters()); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the getRouteParameters() with an external URL. Chris@0: * Chris@0: * @covers ::getRouteParameters Chris@0: */ Chris@0: public function testGetRouteParametersWithExternalUrl() { Chris@0: $url = Url::fromUri('http://example.com'); Chris@0: $this->setExpectedException(\UnexpectedValueException::class); Chris@0: $url->getRouteParameters(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the getOptions() method. Chris@0: * Chris@0: * @param \Drupal\Core\Url[] $urls Chris@0: * An array of Url objects. Chris@0: * Chris@0: * @depends testUrlFromRequest Chris@0: * Chris@0: * @covers ::getOptions Chris@0: */ Chris@0: public function testGetOptions($urls) { Chris@0: foreach ($urls as $index => $url) { Chris@0: $this->assertSame($this->map[$index][2], $url->getOptions()); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the setOptions() method. Chris@0: * Chris@0: * @covers ::setOptions Chris@0: */ Chris@0: public function testSetOptions() { Chris@0: $url = Url::fromRoute('test_route', []); Chris@0: $this->assertEquals([], $url->getOptions()); Chris@0: $url->setOptions(['foo' => 'bar']); Chris@0: $this->assertEquals(['foo' => 'bar'], $url->getOptions()); Chris@0: $url->setOptions([]); Chris@0: $this->assertEquals([], $url->getOptions()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the mergeOptions() method. Chris@0: * Chris@0: * @covers ::mergeOptions Chris@0: */ Chris@0: public function testMergeOptions() { Chris@0: $url = Url::fromRoute('test_route', [], ['foo' => 'bar', 'bar' => ['key' => 'value']]); Chris@0: $url->mergeOptions(['bar' => ['key' => 'value1', 'key2' => 'value2']]); Chris@0: $this->assertEquals(['foo' => 'bar', 'bar' => ['key' => 'value1', 'key2' => 'value2']], $url->getOptions()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the access() method for routed URLs. Chris@0: * Chris@0: * @param bool $access Chris@0: * Chris@0: * @covers ::access Chris@0: * @covers ::accessManager Chris@0: * @dataProvider accessProvider Chris@0: */ Chris@0: public function testAccessRouted($access) { Chris@0: $account = $this->getMock('Drupal\Core\Session\AccountInterface'); Chris@0: $url = new TestUrl('entity.node.canonical', ['node' => 3]); Chris@0: $url->setAccessManager($this->getMockAccessManager($access, $account)); Chris@0: $this->assertEquals($access, $url->access($account)); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the access() method for unrouted URLs (they always have access). Chris@0: * Chris@0: * @covers ::access Chris@0: */ Chris@0: public function testAccessUnrouted() { Chris@0: $account = $this->getMock('Drupal\Core\Session\AccountInterface'); Chris@0: $url = TestUrl::fromUri('base:kittens'); Chris@0: $access_manager = $this->getMock('Drupal\Core\Access\AccessManagerInterface'); Chris@0: $access_manager->expects($this->never()) Chris@0: ->method('checkNamedRoute'); Chris@0: $url->setAccessManager($access_manager); Chris@0: $this->assertTrue($url->access($account)); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the renderAccess() method. Chris@0: * Chris@0: * @param bool $access Chris@0: * Chris@0: * @covers ::renderAccess Chris@0: * @dataProvider accessProvider Chris@0: */ Chris@0: public function testRenderAccess($access) { Chris@0: $element = [ Chris@0: '#url' => Url::fromRoute('entity.node.canonical', ['node' => 3]), Chris@0: ]; Chris@0: $this->container->set('current_user', $this->getMock('Drupal\Core\Session\AccountInterface')); Chris@0: $this->container->set('access_manager', $this->getMockAccessManager($access)); Chris@0: $this->assertEquals($access, TestUrl::renderAccess($element)); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the fromRouteMatch() method. Chris@0: */ Chris@0: public function testFromRouteMatch() { Chris@0: $route = new Route('/test-route/{foo}'); Chris@0: $route_match = new RouteMatch('test_route', $route, ['foo' => (object) [1]], ['foo' => 1]); Chris@0: $url = Url::fromRouteMatch($route_match); Chris@0: $this->assertSame('test_route', $url->getRouteName()); Chris@0: $this->assertEquals(['foo' => '1'], $url->getRouteParameters()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Data provider for testing entity URIs Chris@0: */ Chris@0: public function providerTestEntityUris() { Chris@0: return [ Chris@0: [ Chris@0: 'entity:test_entity/1', Chris@0: [], Chris@0: 'entity.test_entity.canonical', Chris@0: ['test_entity' => '1'], Chris@0: NULL, Chris@0: NULL, Chris@0: ], Chris@0: [ Chris@0: // Ensure a fragment of #0 is handled correctly. Chris@0: 'entity:test_entity/1#0', Chris@0: [], Chris@0: 'entity.test_entity.canonical', Chris@0: ['test_entity' => '1'], Chris@0: NULL, Chris@0: '0', Chris@0: ], Chris@0: // Ensure an empty fragment of # is in options discarded as expected. Chris@0: [ Chris@0: 'entity:test_entity/1', Chris@0: ['fragment' => ''], Chris@0: 'entity.test_entity.canonical', Chris@0: ['test_entity' => '1'], Chris@0: NULL, Chris@0: NULL, Chris@0: ], Chris@0: // Ensure an empty fragment of # in the URI is discarded as expected. Chris@0: [ Chris@0: 'entity:test_entity/1#', Chris@0: [], Chris@0: 'entity.test_entity.canonical', Chris@0: ['test_entity' => '1'], Chris@0: NULL, Chris@0: NULL, Chris@0: ], Chris@0: [ Chris@0: 'entity:test_entity/2?page=1&foo=bar#bottom', Chris@0: [], 'entity.test_entity.canonical', Chris@0: ['test_entity' => '2'], Chris@0: ['page' => '1', 'foo' => 'bar'], Chris@0: 'bottom', Chris@0: ], Chris@0: [ Chris@0: 'entity:test_entity/2?page=1&foo=bar#bottom', Chris@0: ['fragment' => 'top', 'query' => ['foo' => 'yes', 'focus' => 'no']], Chris@0: 'entity.test_entity.canonical', Chris@0: ['test_entity' => '2'], Chris@0: ['page' => '1', 'foo' => 'yes', 'focus' => 'no'], Chris@0: 'top', Chris@0: ], Chris@0: Chris@0: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the fromUri() method with an entity: URI. Chris@0: * Chris@0: * @covers ::fromUri Chris@0: * Chris@0: * @dataProvider providerTestEntityUris Chris@0: */ Chris@0: public function testEntityUris($uri, $options, $route_name, $route_parameters, $query, $fragment) { Chris@0: $url = Url::fromUri($uri, $options); Chris@0: $this->assertSame($route_name, $url->getRouteName()); Chris@0: $this->assertEquals($route_parameters, $url->getRouteParameters()); Chris@0: $this->assertEquals($url->getOption('query'), $query); Chris@0: $this->assertSame($url->getOption('fragment'), $fragment); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the fromUri() method with an invalid entity: URI. Chris@0: * Chris@0: * @covers ::fromUri Chris@0: */ Chris@0: public function testInvalidEntityUriParameter() { Chris@0: // Make the mocked URL generator behave like the actual one. Chris@0: $this->urlGenerator->expects($this->once()) Chris@0: ->method('generateFromRoute') Chris@0: ->with('entity.test_entity.canonical', ['test_entity' => '1/blah']) Chris@0: ->willThrowException(new InvalidParameterException('Parameter "test_entity" for route "/test_entity/{test_entity}" must match "[^/]++" ("1/blah" given) to generate a corresponding URL..')); Chris@0: Chris@0: $this->setExpectedException(InvalidParameterException::class); Chris@0: Url::fromUri('entity:test_entity/1/blah')->toString(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the toUriString() method with entity: URIs. Chris@0: * Chris@0: * @covers ::toUriString Chris@0: * Chris@0: * @dataProvider providerTestToUriStringForEntity Chris@0: */ Chris@0: public function testToUriStringForEntity($uri, $options, $uri_string) { Chris@0: $url = Url::fromUri($uri, $options); Chris@0: $this->assertSame($url->toUriString(), $uri_string); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Data provider for testing string entity URIs Chris@0: */ Chris@0: public function providerTestToUriStringForEntity() { Chris@0: return [ Chris@0: ['entity:test_entity/1', [], 'route:entity.test_entity.canonical;test_entity=1'], Chris@0: ['entity:test_entity/1', ['fragment' => 'top', 'query' => ['page' => '2']], 'route:entity.test_entity.canonical;test_entity=1?page=2#top'], Chris@0: ['entity:test_entity/1?page=2#top', [], 'route:entity.test_entity.canonical;test_entity=1?page=2#top'], Chris@0: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the toUriString() method with internal: URIs. Chris@0: * Chris@0: * @covers ::toUriString Chris@0: * Chris@0: * @dataProvider providerTestToUriStringForInternal Chris@0: */ Chris@0: public function testToUriStringForInternal($uri, $options, $uri_string) { Chris@0: $url = Url::fromRoute('entity.test_entity.canonical', ['test_entity' => '1']); Chris@0: $this->pathValidator->expects($this->any()) Chris@0: ->method('getUrlIfValidWithoutAccessCheck') Chris@0: ->willReturnMap([ Chris@0: ['test-entity/1', $url], Chris@0: ['', Url::fromRoute('')], Chris@0: ['', Url::fromRoute('')], Chris@0: ]); Chris@0: $url = Url::fromUri($uri, $options); Chris@0: $this->assertSame($url->toUriString(), $uri_string); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Data provider for testing internal URIs. Chris@0: */ Chris@0: public function providerTestToUriStringForInternal() { Chris@0: return [ Chris@0: // The four permutations of a regular path. Chris@0: ['internal:/test-entity/1', [], 'route:entity.test_entity.canonical;test_entity=1'], Chris@0: ['internal:/test-entity/1', ['fragment' => 'top'], 'route:entity.test_entity.canonical;test_entity=1#top'], Chris@0: ['internal:/test-entity/1', ['fragment' => 'top', 'query' => ['page' => '2']], 'route:entity.test_entity.canonical;test_entity=1?page=2#top'], Chris@0: ['internal:/test-entity/1?page=2#top', [], 'route:entity.test_entity.canonical;test_entity=1?page=2#top'], Chris@0: Chris@0: // The four permutations of the special '' path. Chris@0: ['internal:/', [], 'route:'], Chris@0: ['internal:/', ['fragment' => 'top'], 'route:#top'], Chris@0: ['internal:/', ['fragment' => 'top', 'query' => ['page' => '2']], 'route:?page=2#top'], Chris@0: ['internal:/?page=2#top', [], 'route:?page=2#top'], Chris@0: Chris@0: // The four permutations of the special '' path. Chris@0: ['internal:', [], 'route:'], Chris@0: ['internal:', ['fragment' => 'top'], 'route:#top'], Chris@0: ['internal:', ['fragment' => 'top', 'query' => ['page' => '2']], 'route:?page=2#top'], Chris@0: ['internal:?page=2#top', [], 'route:?page=2#top'], Chris@0: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the fromUri() method with a valid internal: URI. Chris@0: * Chris@0: * @covers ::fromUri Chris@0: * @dataProvider providerFromValidInternalUri Chris@0: */ Chris@0: public function testFromValidInternalUri($path) { Chris@0: $url = Url::fromUri('internal:' . $path); Chris@0: $this->assertInstanceOf('Drupal\Core\Url', $url); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Data provider for testFromValidInternalUri(). Chris@0: */ Chris@0: public function providerFromValidInternalUri() { Chris@0: return [ Chris@0: // Normal paths with a leading slash. Chris@0: ['/kittens'], Chris@0: ['/kittens/bengal'], Chris@0: // Fragments with and without leading slashes. Chris@0: ['/#about-our-kittens'], Chris@0: ['/kittens#feeding'], Chris@0: ['#feeding'], Chris@0: // Query strings with and without leading slashes. Chris@0: ['/kittens?page=1000'], Chris@0: ['/?page=1000'], Chris@0: ['?page=1000'], Chris@0: ['?breed=bengal&page=1000'], Chris@0: ['?referrer=https://kittenfacts'], Chris@0: // Paths with various token formats but no leading slash. Chris@0: ['/[duckies]'], Chris@0: ['/%bunnies'], Chris@0: ['/{{ puppies }}'], Chris@0: // Disallowed characters in the authority (host name) that are valid Chris@0: // elsewhere in the path. Chris@0: ['/(:;2&+h^'], Chris@0: ['/AKI@&hO@'], Chris@0: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the fromUri() method with an invalid internal: URI. Chris@0: * Chris@0: * @covers ::fromUri Chris@0: * @dataProvider providerFromInvalidInternalUri Chris@0: */ Chris@0: public function testFromInvalidInternalUri($path) { Chris@0: $this->setExpectedException(\InvalidArgumentException::class); Chris@0: Url::fromUri('internal:' . $path); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Data provider for testFromInvalidInternalUri(). Chris@0: */ Chris@0: public function providerFromInvalidInternalUri() { Chris@0: return [ Chris@0: // Normal paths without a leading slash. Chris@0: 'normal_path0' => ['kittens'], Chris@0: 'normal_path1' => ['kittens/bengal'], Chris@0: // Path without a leading slash containing a fragment. Chris@0: 'fragment' => ['kittens#feeding'], Chris@0: // Path without a leading slash containing a query string. Chris@0: 'without_leading_slash_query' => ['kittens?page=1000'], Chris@0: // Paths with various token formats but no leading slash. Chris@0: 'path_with_tokens0' => ['[duckies]'], Chris@0: 'path_with_tokens1' => ['%bunnies'], Chris@0: 'path_with_tokens2' => ['{{ puppies }}'], Chris@0: // Disallowed characters in the authority (host name) that are valid Chris@0: // elsewhere in the path. Chris@0: 'disallowed_hostname_chars0' => ['(:;2&+h^'], Chris@0: 'disallowed_hostname_chars1' => ['AKI@&hO@'], Chris@0: // Leading slash with a domain. Chris@0: 'leading_slash_with_domain' => ['/http://example.com'], Chris@0: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the fromUri() method with a base: URI starting with a number. Chris@0: * Chris@0: * @covers ::fromUri Chris@0: */ Chris@0: public function testFromUriNumber() { Chris@0: $url = Url::fromUri('base:2015/10/06'); Chris@0: $this->assertSame($url->toUriString(), 'base:/2015/10/06'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the toUriString() method with route: URIs. Chris@0: * Chris@0: * @covers ::toUriString Chris@0: * Chris@0: * @dataProvider providerTestToUriStringForRoute Chris@0: */ Chris@0: public function testToUriStringForRoute($uri, $options, $uri_string) { Chris@0: $url = Url::fromUri($uri, $options); Chris@0: $this->assertSame($url->toUriString(), $uri_string); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Data provider for testing route: URIs. Chris@0: */ Chris@0: public function providerTestToUriStringForRoute() { Chris@0: return [ Chris@0: ['route:entity.test_entity.canonical;test_entity=1', [], 'route:entity.test_entity.canonical;test_entity=1'], Chris@0: ['route:entity.test_entity.canonical;test_entity=1', ['fragment' => 'top', 'query' => ['page' => '2']], 'route:entity.test_entity.canonical;test_entity=1?page=2#top'], Chris@0: ['route:entity.test_entity.canonical;test_entity=1?page=2#top', [], 'route:entity.test_entity.canonical;test_entity=1?page=2#top'], Chris@0: // Check that an empty fragment is discarded. Chris@0: ['route:entity.test_entity.canonical;test_entity=1?page=2#', [], 'route:entity.test_entity.canonical;test_entity=1?page=2'], Chris@0: // Check that an empty fragment is discarded. Chris@0: ['route:entity.test_entity.canonical;test_entity=1?page=2', ['fragment' => ''], 'route:entity.test_entity.canonical;test_entity=1?page=2'], Chris@0: // Check that a fragment of #0 is preserved. Chris@0: ['route:entity.test_entity.canonical;test_entity=1?page=2#0', [], 'route:entity.test_entity.canonical;test_entity=1?page=2#0'], Chris@0: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * @covers ::fromUri Chris@0: */ Chris@0: public function testFromRouteUriWithMissingRouteName() { Chris@0: $this->setExpectedException(\InvalidArgumentException::class, "The route URI 'route:' is invalid."); Chris@0: Url::fromUri('route:'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Creates a mock access manager for the access tests. Chris@0: * Chris@0: * @param bool $access Chris@0: * @param \Drupal\Core\Session\AccountInterface|null $account Chris@0: * Chris@0: * @return \Drupal\Core\Access\AccessManagerInterface|\PHPUnit_Framework_MockObject_MockObject Chris@0: */ Chris@0: protected function getMockAccessManager($access, $account = NULL) { Chris@0: $access_manager = $this->getMock('Drupal\Core\Access\AccessManagerInterface'); Chris@0: $access_manager->expects($this->once()) Chris@0: ->method('checkNamedRoute') Chris@0: ->with('entity.node.canonical', ['node' => 3], $account) Chris@0: ->willReturn($access); Chris@0: return $access_manager; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Data provider for the access test methods. Chris@0: */ Chris@0: public function accessProvider() { Chris@0: return [ Chris@0: [TRUE], Chris@0: [FALSE], Chris@0: ]; Chris@0: } Chris@0: Chris@0: } Chris@0: Chris@0: class TestUrl extends Url { Chris@0: Chris@0: /** Chris@0: * Sets the access manager. Chris@0: * Chris@0: * @param \Drupal\Core\Access\AccessManagerInterface $access_manager Chris@0: */ Chris@0: public function setAccessManager(AccessManagerInterface $access_manager) { Chris@0: $this->accessManager = $access_manager; Chris@0: } Chris@0: Chris@0: }