'drupal_alter() tests',
      'description' => 'Confirm that alteration of arguments passed to drupal_alter() works correctly.',
      'group' => 'System',
    );
  }
  function setUp() {
    parent::setUp('common_test');
  }
  function testDrupalAlter() {
    // This test depends on Bartik, so make sure that it is always the current
    // active theme.
    global $theme, $base_theme_info;
    $theme = 'bartik';
    $base_theme_info = array();
    $array = array('foo' => 'bar');
    $entity = new stdClass();
    $entity->foo = 'bar';
    // Verify alteration of a single argument.
    $array_copy = $array;
    $array_expected = array('foo' => 'Drupal theme');
    drupal_alter('drupal_alter', $array_copy);
    $this->assertEqual($array_copy, $array_expected, 'Single array was altered.');
    $entity_copy = clone $entity;
    $entity_expected = clone $entity;
    $entity_expected->foo = 'Drupal theme';
    drupal_alter('drupal_alter', $entity_copy);
    $this->assertEqual($entity_copy, $entity_expected, 'Single object was altered.');
    // Verify alteration of multiple arguments.
    $array_copy = $array;
    $array_expected = array('foo' => 'Drupal theme');
    $entity_copy = clone $entity;
    $entity_expected = clone $entity;
    $entity_expected->foo = 'Drupal theme';
    $array2_copy = $array;
    $array2_expected = array('foo' => 'Drupal theme');
    drupal_alter('drupal_alter', $array_copy, $entity_copy, $array2_copy);
    $this->assertEqual($array_copy, $array_expected, 'First argument to drupal_alter() was altered.');
    $this->assertEqual($entity_copy, $entity_expected, 'Second argument to drupal_alter() was altered.');
    $this->assertEqual($array2_copy, $array2_expected, 'Third argument to drupal_alter() was altered.');
    // Verify alteration order when passing an array of types to drupal_alter().
    // common_test_module_implements_alter() places 'block' implementation after
    // other modules.
    $array_copy = $array;
    $array_expected = array('foo' => 'Drupal block theme');
    drupal_alter(array('drupal_alter', 'drupal_alter_foo'), $array_copy);
    $this->assertEqual($array_copy, $array_expected, 'hook_TYPE_alter() implementations ran in correct order.');
  }
}
/**
 * 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 CommonURLUnitTest extends DrupalWebTestCase {
  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' => 'System',
    );
  }
  /**
   * Confirm that invalid text given as $path is filtered.
   */
  function testLXSS() {
    $text = $this->randomName();
    $path = "";
    $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() {
    $link = l($this->randomName(), $_GET['q']);
    $this->assertTrue($this->hasClass($link, 'active'), format_string('Class @class is present on link to the current page', array('@class' => 'active')));
  }
  /**
   * Tests for custom class in l() function.
   */
  function testLCustomClass() {
    $class = $this->randomName();
    $link = l($this->randomName(), $_GET['q'], 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)));
    $this->assertTrue($this->hasClass($link, 'active'), format_string('Class @class is present on link to the current page', array('@class' => 'active')));
  }
  private function hasClass($link, $class) {
    return preg_match('|class="([^\"\s]+\s+)*' . $class . '|', $link);
  }
  /**
   * Test drupal_get_query_parameters().
   */
  function testDrupalGetQueryParameters() {
    $original = array(
      'a' => 1,
      'b' => array(
        'd' => 4,
        'e' => array(
          'f' => 5,
        ),
      ),
      'c' => 3,
      'q' => 'foo/bar',
    );
    // Default arguments.
    $result = $_GET;
    unset($result['q']);
    $this->assertEqual(drupal_get_query_parameters(), $result, "\$_GET['q'] was removed.");
    // Default exclusion.
    $result = $original;
    unset($result['q']);
    $this->assertEqual(drupal_get_query_parameters($original), $result, "'q' was removed.");
    // 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.");
  }
  /**
   * Test 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.');
  }
  /**
   * Test drupal_parse_url().
   */
  function testDrupalParseUrl() {
    // Relative URL.
    $url = 'foo/bar?foo=bar&bar=baz&baz#foo';
    $result = array(
      'path' => 'foo/bar',
      'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''),
      'fragment' => 'foo',
    );
    $this->assertEqual(drupal_parse_url($url), $result, 'Relative 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.');
    // Absolute URL.
    $url = '/foo/bar?foo=bar&bar=baz&baz#foo';
    $result = array(
      'path' => '/foo/bar',
      'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''),
      'fragment' => 'foo',
    );
    $this->assertEqual(drupal_parse_url($url), $result, 'Absolute URL parsed correctly.');
    // External URL testing.
    $url = 'http://drupal.org/foo/bar?foo=bar&bar=baz&baz#foo';
    // Test that drupal can recognize an absolute URL. Used to prevent attack vectors.
    $this->assertTrue(url_is_external($url), 'Correctly identified an external URL.');
    // External URL without an explicit protocol.
    $url = '//drupal.org/foo/bar?foo=bar&bar=baz&baz#foo';
    $this->assertTrue(url_is_external($url), 'Correctly identified an external URL without a protocol part.');
    // Internal URL starting with a slash.
    $url = '/drupal.org';
    $this->assertFalse(url_is_external($url), 'Correctly identified an internal URL with a leading slash.');
    // Test the parsing of absolute URLs.
    $url = 'http://drupal.org/foo/bar?foo=bar&bar=baz&baz#foo';
    $result = array(
      'path' => 'http://drupal.org/foo/bar',
      'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''),
      'fragment' => 'foo',
    );
    $this->assertEqual(drupal_parse_url($url), $result, 'External URL parsed correctly.');
    // Verify proper parsing of URLs when clean URLs are disabled.
    $result = array(
      'path' => 'foo/bar',
      'query' => array('bar' => 'baz'),
      'fragment' => 'foo',
    );
    // Non-clean URLs #1: Absolute URL generated by url().
    $url = $GLOBALS['base_url'] . '/?q=foo/bar&bar=baz#foo';
    $this->assertEqual(drupal_parse_url($url), $result, 'Absolute URL with clean URLs disabled parsed correctly.');
    // Non-clean URLs #2: Relative URL generated by url().
    $url = '?q=foo/bar&bar=baz#foo';
    $this->assertEqual(drupal_parse_url($url), $result, 'Relative URL with clean URLs disabled parsed correctly.');
    // Non-clean URLs #3: URL generated by url() on non-Apache webserver.
    $url = 'index.php?q=foo/bar&bar=baz#foo';
    $this->assertEqual(drupal_parse_url($url), $result, 'Relative URL on non-Apache webserver with clean URLs disabled parsed correctly.');
    // 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.');
  }
  /**
   * Test url() with/without query, with/without fragment, absolute on/off and
   * assert all that works when clean URLs are on and off.
   */
  function testUrl() {
    global $base_url;
    foreach (array(FALSE, TRUE) as $absolute) {
      // Get the expected start of the path string.
      $base = $absolute ? $base_url . '/' : base_path();
      $absolute_string = $absolute ? 'absolute' : NULL;
      // Disable Clean URLs.
      $GLOBALS['conf']['clean_url'] = 0;
      $url = $base . '?q=node/123';
      $result = url('node/123', array('absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");
      $url = $base . '?q=node/123#foo';
      $result = url('node/123', array('fragment' => 'foo', 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");
      $url = $base . '?q=node/123&foo';
      $result = url('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");
      $url = $base . '?q=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 . '?q=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 . '?q=node/123&foo#0';
      $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => '0', 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");
      $url = $base . '?q=node/123&foo';
      $result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => '', 'absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");
      $url = $base;
      $result = url('', array('absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");
      // Enable Clean URLs.
      $GLOBALS['conf']['clean_url'] = 1;
      $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('', array('absolute' => $absolute));
      $this->assertEqual($url, $result, "$url == $result");
    }
  }
  /**
   * Test 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.');
    // Verify that an internal URL does not result in an external URL without
    // protocol part.
    $url = '/drupal.org';
    $result = url($url);
    $this->assertTrue(strpos($result, '//') === FALSE, 'Internal URL does not turn into an external URL.');
    // Verify that an external URL without protocol part is recognized as such.
    $url = '//drupal.org';
    $result = url($url);
    $this->assertEqual($url, $result, 'External URL without protocol is not altered.');
  }
}
/**
 * Tests url_is_external().
 */
class UrlIsExternalUnitTest extends DrupalUnitTestCase {
  public static function getInfo() {
    return array(
      'name' => 'External URL checking',
      'description' => 'Performs tests on url_is_external().',
      'group' => 'System',
    );
  }
  /**
   * Tests if each URL is external or not.
   */
  function testUrlIsExternal() {
    foreach ($this->examples() as $path => $expected) {
      $this->assertIdentical(url_is_external($path), $expected, $path);
    }
  }
  /**
   * Provides data for testUrlIsExternal().
   *
   * @return array
   *   An array of test data, keyed by a path, with the expected value where
   *   TRUE is external, and FALSE is not external.
   */
  protected function examples() {
    return array(
      // Simple external URLs.
      'http://example.com' => TRUE,
      'https://example.com' => TRUE,
      'http://drupal.org/foo/bar?foo=bar&bar=baz&baz#foo' => TRUE,
      '//drupal.org' => TRUE,
      // Some browsers ignore or strip leading control characters.
      "\x00//www.example.com" => TRUE,
      "\x08//www.example.com" => TRUE,
      "\x1F//www.example.com" => TRUE,
      "\n//www.example.com" => TRUE,
      // JSON supports decoding directly from UTF-8 code points.
      json_decode('"\u00AD"') . "//www.example.com" => TRUE,
      json_decode('"\u200E"') . "//www.example.com" => TRUE,
      json_decode('"\uE0020"') . "//www.example.com" => TRUE,
      json_decode('"\uE000"')  . "//www.example.com" => TRUE,
      // Backslashes should be normalized to forward.
      '\\\\example.com' => TRUE,
      // Local URLs.
      'node' => FALSE,
      '/system/ajax' => FALSE,
      '?q=foo:bar' => FALSE,
      'node/edit:me' => FALSE,
      '/drupal.org' => FALSE,
      '' => FALSE,
    );
  }
}
/**
 * Tests for check_plain(), filter_xss(), format_string(), and check_url().
 */
class CommonXssUnitTest extends DrupalUnitTestCase {
  public static function getInfo() {
    return array(
      'name' => 'String filtering tests',
      'description' => 'Confirm that check_plain(), filter_xss(), format_string() and check_url() work correctly, including invalid multi-byte sequences.',
      'group' => 'System',
    );
  }
  /**
   * Check that invalid multi-byte sequences are rejected.
   */
  function testInvalidMultiByte() {
     // Ignore PHP 5.3+ invalid multibyte sequence warning.
     $text = @check_plain("Foo\xC0barbaz");
     $this->assertEqual($text, '', 'check_plain() rejects invalid sequence "Foo\xC0barbaz"');
     // Ignore PHP 5.3+ invalid multibyte sequence warning.
     $text = @check_plain("\xc2\"");
     $this->assertEqual($text, '', 'check_plain() rejects invalid sequence "\xc2\""');
     $text = check_plain("Fooÿñ");
     $this->assertEqual($text, "Fooÿñ", 'check_plain() accepts valid sequence "Fooÿñ"');
     $text = filter_xss("Foo\xC0barbaz");
     $this->assertEqual($text, '', 'filter_xss() rejects invalid sequence "Foo\xC0barbaz"');
     $text = filter_xss("Fooÿñ");
     $this->assertEqual($text, "Fooÿñ", 'filter_xss() accepts valid sequence Fooÿñ');
  }
  /**
   * Check that special characters are escaped.
   */
  function testEscaping() {
     $text = check_plain("