'Drupal match path', 'description' => 'Tests the drupal_match_path() function to make sure it works properly.', 'group' => 'Path API', ); } function setUp() { // Set up the database and testing environment. parent::setUp(); // Set up a random site front page to test the '' placeholder. $this->front = $this->randomName(); variable_set('site_frontpage', $this->front); // Refresh our static variables from the database. $this->refreshVariables(); } /** * Run through our test cases, making sure each one works as expected. */ function testDrupalMatchPath() { // Set up our test cases. $tests = $this->drupalMatchPathTests(); foreach ($tests as $patterns => $cases) { foreach ($cases as $path => $expected_result) { $actual_result = drupal_match_path($path, $patterns); $this->assertIdentical($actual_result, $expected_result, format_string('Tried matching the path @path to the pattern
@patterns
- expected @expected, got @actual.', array('@path' => $path, '@patterns' => $patterns, '@expected' => var_export($expected_result, TRUE), '@actual' => var_export($actual_result, TRUE)))); } } } /** * Helper function for testDrupalMatchPath(): set up an array of test cases. * * @return * An array of test cases to cycle through. */ private function drupalMatchPathTests() { return array( // Single absolute paths. 'blog/1' => array( 'blog/1' => TRUE, 'blog/2' => FALSE, 'test' => FALSE, ), // Single paths with wildcards. 'blog/*' => array( 'blog/1' => TRUE, 'blog/2' => TRUE, 'blog/3/edit' => TRUE, 'blog/' => TRUE, 'blog' => FALSE, 'test' => FALSE, ), // Single paths with multiple wildcards. 'node/*/revisions/*' => array( 'node/1/revisions/3' => TRUE, 'node/345/revisions/test' => TRUE, 'node/23/edit' => FALSE, 'test' => FALSE, ), // Single paths with ''. '' => array( $this->front => TRUE, "$this->front/" => FALSE, "$this->front/edit" => FALSE, 'node' => FALSE, '' => FALSE, ), // Paths with both '' and wildcards (should not work). '/*' => array( $this->front => FALSE, "$this->front/" => FALSE, "$this->front/edit" => FALSE, 'node/12' => FALSE, '' => FALSE, ), // Multiple paths with the \n delimiter. "node/*\nnode/*/edit" => array( 'node/1' => TRUE, 'node/view' => TRUE, 'node/32/edit' => TRUE, 'node/delete/edit' => TRUE, 'node/50/delete' => TRUE, 'test/example' => FALSE, ), // Multiple paths with the \r delimiter. "user/*\rblog/*" => array( 'user/1' => TRUE, 'blog/1' => TRUE, 'user/1/blog/1' => TRUE, 'user/blog' => TRUE, 'test/example' => FALSE, 'user' => FALSE, 'blog' => FALSE, ), // Multiple paths with the \r\n delimiter. "test\r\n" => array( 'test' => TRUE, $this->front => TRUE, 'example' => FALSE, ), // Test existing regular expressions (should be escaped). '[^/]+?/[0-9]' => array( 'test/1' => FALSE, '[^/]+?/[0-9]' => TRUE, ), ); } } /** * Tests hook_url_alter functions. */ class UrlAlterFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => t('URL altering'), 'description' => t('Tests hook_url_inbound_alter() and hook_url_outbound_alter().'), 'group' => t('Path API'), ); } function setUp() { parent::setUp('path', 'forum', 'url_alter_test'); } /** * Test that URL altering works and that it occurs in the correct order. */ function testUrlAlter() { $account = $this->drupalCreateUser(array('administer url aliases')); $this->drupalLogin($account); $uid = $account->uid; $name = $account->name; // Test a single altered path. $this->assertUrlInboundAlter("user/$name", "user/$uid"); $this->assertUrlOutboundAlter("user/$uid", "user/$name"); // Test that a path always uses its alias. $path = array('source' => "user/$uid/test1", 'alias' => 'alias/test1'); path_save($path); $this->assertUrlInboundAlter('alias/test1', "user/$uid/test1"); $this->assertUrlOutboundAlter("user/$uid/test1", 'alias/test1'); // Test that alias source paths are normalized in the interface. $edit = array('source' => "user/$name/edit", 'alias' => 'alias/test2'); $this->drupalPost('admin/config/search/path/add', $edit, t('Save')); $this->assertText(t('The alias has been saved.')); // Test that a path always uses its alias. $this->assertUrlInboundAlter('alias/test2', "user/$uid/edit"); $this->assertUrlOutboundAlter("user/$uid/edit", 'alias/test2'); // Test a non-existent user is not altered. $uid++; $this->assertUrlInboundAlter("user/$uid", "user/$uid"); $this->assertUrlOutboundAlter("user/$uid", "user/$uid"); // Test that 'forum' is altered to 'community' correctly, both at the root // level and for a specific existing forum. $this->assertUrlInboundAlter('community', 'forum'); $this->assertUrlOutboundAlter('forum', 'community'); $forum_vid = db_query("SELECT vid FROM {taxonomy_vocabulary} WHERE module = 'forum'")->fetchField(); $tid = db_insert('taxonomy_term_data') ->fields(array( 'name' => $this->randomName(), 'vid' => $forum_vid, )) ->execute(); $this->assertUrlInboundAlter("community/$tid", "forum/$tid"); $this->assertUrlOutboundAlter("forum/$tid", "community/$tid"); } /** * Test current_path() and request_path(). */ function testCurrentUrlRequestedPath() { $this->drupalGet('url-alter-test/bar'); $this->assertRaw('request_path=url-alter-test/bar', 'request_path() returns the requested path.'); $this->assertRaw('current_path=url-alter-test/foo', 'current_path() returns the internal path.'); } /** * Tests that $_GET['q'] is initialized when the request path is empty. */ function testGetQInitialized() { $this->drupalGet(''); $this->assertText("\$_GET['q'] is non-empty with an empty request path.", "\$_GET['q'] is initialized with an empty request path."); } /** * Assert that an outbound path is altered to an expected value. * * @param $original * A string with the original path that is run through url(). * @param $final * A string with the expected result after url(). * @return * TRUE if $original was correctly altered to $final, FALSE otherwise. */ protected function assertUrlOutboundAlter($original, $final) { // Test outbound altering. $result = url($original); $base_path = base_path() . (variable_get('clean_url', '0') ? '' : '?q='); $result = substr($result, strlen($base_path)); $this->assertIdentical($result, $final, format_string('Altered outbound URL %original, expected %final, and got %result.', array('%original' => $original, '%final' => $final, '%result' => $result))); } /** * Assert that a inbound path is altered to an expected value. * * @param $original * A string with the aliased or un-normal path that is run through * drupal_get_normal_path(). * @param $final * A string with the expected result after url(). * @return * TRUE if $original was correctly altered to $final, FALSE otherwise. */ protected function assertUrlInboundAlter($original, $final) { // Test inbound altering. $result = drupal_get_normal_path($original); $this->assertIdentical($result, $final, format_string('Altered inbound URL %original, expected %final, and got %result.', array('%original' => $original, '%final' => $final, '%result' => $result))); } } /** * Unit test for drupal_lookup_path(). */ class PathLookupTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => t('Path lookup'), 'description' => t('Tests that drupal_lookup_path() returns correct paths.'), 'group' => t('Path API'), ); } /** * Test that drupal_lookup_path() returns the correct path. */ function testDrupalLookupPath() { $account = $this->drupalCreateUser(); $uid = $account->uid; $name = $account->name; // Test the situation where the source is the same for multiple aliases. // Start with a language-neutral alias, which we will override. $path = array( 'source' => "user/$uid", 'alias' => 'foo', ); path_save($path); $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'Basic alias lookup works.'); $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Basic source lookup works.'); // Create a language specific alias for the default language (English). $path = array( 'source' => "user/$uid", 'alias' => "users/$name", 'language' => 'en', ); path_save($path); $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'English alias overrides language-neutral alias.'); $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'English source overrides language-neutral source.'); // Create a language-neutral alias for the same path, again. $path = array( 'source' => "user/$uid", 'alias' => 'bar', ); path_save($path); $this->assertEqual(drupal_lookup_path('alias', $path['source']), "users/$name", 'English alias still returned after entering a language-neutral alias.'); // Create a language-specific (xx-lolspeak) alias for the same path. $path = array( 'source' => "user/$uid", 'alias' => 'LOL', 'language' => 'xx-lolspeak', ); path_save($path); $this->assertEqual(drupal_lookup_path('alias', $path['source']), "users/$name", 'English alias still returned after entering a LOLspeak alias.'); // The LOLspeak alias should be returned if we really want LOLspeak. $this->assertEqual(drupal_lookup_path('alias', $path['source'], 'xx-lolspeak'), 'LOL', 'LOLspeak alias returned if we specify xx-lolspeak to drupal_lookup_path().'); // Create a new alias for this path in English, which should override the // previous alias for "user/$uid". $path = array( 'source' => "user/$uid", 'alias' => 'users/my-new-path', 'language' => 'en', ); path_save($path); $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'Recently created English alias returned.'); $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Recently created English source returned.'); // Remove the English aliases, which should cause a fallback to the most // recently created language-neutral alias, 'bar'. db_delete('url_alias') ->condition('language', 'en') ->execute(); drupal_clear_path_cache(); $this->assertEqual(drupal_lookup_path('alias', $path['source']), 'bar', 'Path lookup falls back to recently created language-neutral alias.'); // Test the situation where the alias and language are the same, but // the source differs. The newer alias record should be returned. $account2 = $this->drupalCreateUser(); $path = array( 'source' => 'user/' . $account2->uid, 'alias' => 'bar', ); path_save($path); $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Newer alias record is returned when comparing two LANGUAGE_NONE paths with the same alias.'); // Test if the alias returned by drupal_lookup_path() is the same as the // alias returned by path_load(). $path = array( 'source' => 'user/' . $account2->uid, 'alias' => 'bar2', ); path_save($path); $this->assertEqual(drupal_lookup_path('alias', $path['source']), 'bar2', 'Newer alias record is returned when using drupal_lookup_path() on paths with multiple aliases.'); $loaded_path = path_load(array('source' => $path['source'])); $this->assertEqual($loaded_path['alias'], 'bar2', 'Newer alias record is returned when using path_load() on paths with multiple aliases.'); } } /** * Tests the path_save() function. */ class PathSaveTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => t('Path save'), 'description' => t('Tests that path_save() exposes the previous alias value.'), 'group' => t('Path API'), ); } function setUp() { // Enable a helper module that implements hook_path_update(). parent::setUp('path_test'); path_test_reset(); } /** * Tests that path_save() makes the original path available to modules. */ function testDrupalSaveOriginalPath() { $account = $this->drupalCreateUser(); $uid = $account->uid; $name = $account->name; // Create a language-neutral alias. $path = array( 'source' => "user/$uid", 'alias' => 'foo', ); $path_original = $path; path_save($path); // Alter the path. $path['alias'] = 'bar'; path_save($path); // Test to see if the original alias is available to modules during // hook_path_update(). $results = variable_get('path_test_results', array()); $this->assertIdentical($results['hook_path_update']['original']['alias'], $path_original['alias'], 'Old path alias available to modules during hook_path_update.'); $this->assertIdentical($results['hook_path_update']['original']['source'], $path_original['source'], 'Old path alias available to modules during hook_path_update.'); } }