Definition of Drupal\system\Tests\Common\UrlTest.
<?php
/**
* @file
* Definition of Drupal\system\Tests\Common\UrlTest.
*/
namespace Drupal\system\Tests\Common;
use Drupal\simpletest\WebTestBase;
/**
* Tests for URL generation functions.
*
* url() calls module_implements(), which may issue a db query, which requires
* inheriting from a web test case rather than a unit test case.
*/
class UrlTest extends WebTestBase {
public static $modules = array(
'common_test',
);
public static function getInfo() {
return array(
'name' => 'URL generation tests',
'description' => 'Confirm that url(), drupal_get_query_parameters(), drupal_http_build_query(), and l() work correctly with various input.',
'group' => 'Common',
);
}
/**
* Confirms that invalid URLs are filtered.
*/
function testLXSS() {
$text = $this
->randomName();
$path = "<SCRIPT>alert('XSS')</SCRIPT>";
$link = l($text, $path);
$sanitized_path = check_url(url($path));
$this
->assertTrue(strpos($link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered', array(
'@path' => $path,
)));
}
/**
* Tests for active class in l() function.
*/
function testLActiveClass() {
$path = 'common-test/l-active-class';
$options = array();
$this
->drupalGet($path, $options);
$links = $this
->xpath('//a[@href = :href and contains(@class, :class)]', array(
':href' => url($path, $options),
':class' => 'active',
));
$this
->assertTrue(isset($links[0]), 'A link to the current page is marked active.');
$options = array(
'query' => array(
'foo' => 'bar',
),
);
$links = $this
->xpath('//a[@href = :href and not(contains(@class, :class))]', array(
':href' => url($path, $options),
':class' => 'active',
));
$this
->assertTrue(isset($links[0]), 'A link to the current page with a query string when the current page has no query string is not marked active.');
$this
->drupalGet($path, $options);
$links = $this
->xpath('//a[@href = :href and contains(@class, :class)]', array(
':href' => url($path, $options),
':class' => 'active',
));
$this
->assertTrue(isset($links[0]), 'A link to the current page with a query string that matches the current query string is marked active.');
$options = array();
$links = $this
->xpath('//a[@href = :href and not(contains(@class, :class))]', array(
':href' => url($path, $options),
':class' => 'active',
));
$this
->assertTrue(isset($links[0]), 'A link to the current page without a query string when the current page has a query string is not marked active.');
}
/**
* Tests for custom class in l() function.
*/
function testLCustomClass() {
$class = $this
->randomName();
$link = l($this
->randomName(), current_path(), array(
'attributes' => array(
'class' => array(
$class,
),
),
));
$this
->assertTrue($this
->hasClass($link, $class), format_string('Custom class @class is present on link when requested', array(
'@class' => $class,
)));
}
/**
* Checks for class existence in link.
*
* @param $link
* URL to search.
* @param $class
* Element class to search for.
*
* @return bool
* TRUE if the class is found, FALSE otherwise.
*/
private function hasClass($link, $class) {
return preg_match('|class="([^\\"\\s]+\\s+)*' . $class . '|', $link);
}
/**
* Tests drupal_get_query_parameters().
*/
function testDrupalGetQueryParameters() {
$original = array(
'a' => 1,
'b' => array(
'd' => 4,
'e' => array(
'f' => 5,
),
),
'c' => 3,
);
// First-level exclusion.
$result = $original;
unset($result['b']);
$this
->assertEqual(drupal_get_query_parameters($original, array(
'b',
)), $result, "'b' was removed.");
// Second-level exclusion.
$result = $original;
unset($result['b']['d']);
$this
->assertEqual(drupal_get_query_parameters($original, array(
'b[d]',
)), $result, "'b[d]' was removed.");
// Third-level exclusion.
$result = $original;
unset($result['b']['e']['f']);
$this
->assertEqual(drupal_get_query_parameters($original, array(
'b[e][f]',
)), $result, "'b[e][f]' was removed.");
// Multiple exclusions.
$result = $original;
unset($result['a'], $result['b']['e'], $result['c']);
$this
->assertEqual(drupal_get_query_parameters($original, array(
'a',
'b[e]',
'c',
)), $result, "'a', 'b[e]', 'c' were removed.");
}
/**
* Tests drupal_http_build_query().
*/
function testDrupalHttpBuildQuery() {
$this
->assertEqual(drupal_http_build_query(array(
'a' => ' &#//+%20@۞',
)), 'a=%20%26%23//%2B%2520%40%DB%9E', 'Value was properly encoded.');
$this
->assertEqual(drupal_http_build_query(array(
' &#//+%20@۞' => 'a',
)), '%20%26%23%2F%2F%2B%2520%40%DB%9E=a', 'Key was properly encoded.');
$this
->assertEqual(drupal_http_build_query(array(
'a' => '1',
'b' => '2',
'c' => '3',
)), 'a=1&b=2&c=3', 'Multiple values were properly concatenated.');
$this
->assertEqual(drupal_http_build_query(array(
'a' => array(
'b' => '2',
'c' => '3',
),
'd' => 'foo',
)), 'a[b]=2&a[c]=3&d=foo', 'Nested array was properly encoded.');
}
/**
* Tests drupal_parse_url().
*/
function testDrupalParseUrl() {
// Relative, absolute, and external URLs, without/with explicit script path,
// without/with Drupal path.
foreach (array(
'',
'/',
'http://drupal.org/',
) as $absolute) {
foreach (array(
'',
'index.php/',
) as $script) {
foreach (array(
'',
'foo/bar',
) as $path) {
$url = $absolute . $script . $path . '?foo=bar&bar=baz&baz#foo';
$expected = array(
'path' => $absolute . $script . $path,
'query' => array(
'foo' => 'bar',
'bar' => 'baz',
'baz' => '',
),
'fragment' => 'foo',
);
$this
->assertEqual(drupal_parse_url($url), $expected, 'URL parsed correctly.');
}
}
}
// Relative URL that is known to confuse parse_url().
$url = 'foo/bar:1';
$result = array(
'path' => 'foo/bar:1',
'query' => array(),
'fragment' => '',
);
$this
->assertEqual(drupal_parse_url($url), $result, 'Relative URL parsed correctly.');
// Test that drupal can recognize an absolute URL. Used to prevent attack vectors.
$url = 'http://drupal.org/foo/bar?foo=bar&bar=baz&baz#foo';
$this
->assertTrue(url_is_external($url), 'Correctly identified an external URL.');
// Test that drupal_parse_url() does not allow spoofing a URL to force a malicious redirect.
$parts = drupal_parse_url('forged:http://cwe.mitre.org/data/definitions/601.html');
$this
->assertFalse(valid_url($parts['path'], TRUE), 'drupal_parse_url() correctly parsed a forged URL.');
}
/**
* Tests url() functionality.
*
* Tests url() with/without query, with/without fragment, absolute on/off and
* asserts all that works when clean URLs are on and off.
*/
function testUrl() {
global $base_url, $script_path;
$script_path_original = $script_path;
foreach (array(
'',
'index.php/',
) as $script_path) {
foreach (array(
FALSE,
TRUE,
) as $absolute) {
// Get the expected start of the path string.
$base = ($absolute ? $base_url . '/' : base_path()) . $script_path;
$absolute_string = $absolute ? 'absolute' : NULL;
$url = $base . 'node/123';
$result = url('node/123', array(
'absolute' => $absolute,
));
$this
->assertEqual($url, $result, "{$url} == {$result}");
$url = $base . 'node/123#foo';
$result = url('node/123', array(
'fragment' => 'foo',
'absolute' => $absolute,
));
$this
->assertEqual($url, $result, "{$url} == {$result}");
$url = $base . 'node/123?foo';
$result = url('node/123', array(
'query' => array(
'foo' => NULL,
),
'absolute' => $absolute,
));
$this
->assertEqual($url, $result, "{$url} == {$result}");
$url = $base . 'node/123?foo=bar&bar=baz';
$result = url('node/123', array(
'query' => array(
'foo' => 'bar',
'bar' => 'baz',
),
'absolute' => $absolute,
));
$this
->assertEqual($url, $result, "{$url} == {$result}");
$url = $base . 'node/123?foo#bar';
$result = url('node/123', array(
'query' => array(
'foo' => NULL,
),
'fragment' => 'bar',
'absolute' => $absolute,
));
$this
->assertEqual($url, $result, "{$url} == {$result}");
$url = $base;
$result = url('<front>', array(
'absolute' => $absolute,
));
$this
->assertEqual($url, $result, "{$url} == {$result}");
}
}
$script_path = $script_path_original;
}
/**
* Tests external URL handling.
*/
function testExternalUrls() {
$test_url = 'http://drupal.org/';
// Verify external URL can contain a fragment.
$url = $test_url . '#drupal';
$result = url($url);
$this
->assertEqual($url, $result, 'External URL with fragment works without a fragment in $options.');
// Verify fragment can be overidden in an external URL.
$url = $test_url . '#drupal';
$fragment = $this
->randomName(10);
$result = url($url, array(
'fragment' => $fragment,
));
$this
->assertEqual($test_url . '#' . $fragment, $result, 'External URL fragment is overidden with a custom fragment in $options.');
// Verify external URL can contain a query string.
$url = $test_url . '?drupal=awesome';
$result = url($url);
$this
->assertEqual($url, $result, 'External URL with query string works without a query string in $options.');
// Verify external URL can be extended with a query string.
$url = $test_url;
$query = array(
$this
->randomName(5) => $this
->randomName(5),
);
$result = url($url, array(
'query' => $query,
));
$this
->assertEqual($url . '?' . http_build_query($query, '', '&'), $result, 'External URL can be extended with a query string in $options.');
// Verify query string can be extended in an external URL.
$url = $test_url . '?drupal=awesome';
$query = array(
$this
->randomName(5) => $this
->randomName(5),
);
$result = url($url, array(
'query' => $query,
));
$this
->assertEqual($url . '&' . http_build_query($query, '', '&'), $result, 'External URL query string can be extended with a custom query string in $options.');
}
}