| Drupal | PHP Cross Reference | Content Management Systems |
1 <?php 2 3 /** 4 * @file 5 * Tests for the Path module. 6 */ 7 8 /** 9 * Provides a base class for testing the Path module. 10 */ 11 class PathTestCase extends DrupalWebTestCase { 12 public static function getInfo() { 13 return array( 14 'name' => 'Path alias functionality', 15 'description' => 'Add, edit, delete, and change alias and verify its consistency in the database.', 16 'group' => 'Path', 17 ); 18 } 19 20 function setUp() { 21 parent::setUp('path'); 22 23 // Create test user and login. 24 $web_user = $this->drupalCreateUser(array('create page content', 'edit own page content', 'administer url aliases', 'create url aliases')); 25 $this->drupalLogin($web_user); 26 } 27 28 /** 29 * Tests the path cache. 30 */ 31 function testPathCache() { 32 // Create test node. 33 $node1 = $this->drupalCreateNode(); 34 35 // Create alias. 36 $edit = array(); 37 $edit['source'] = 'node/' . $node1->nid; 38 $edit['alias'] = $this->randomName(8); 39 $this->drupalPost('admin/config/search/path/add', $edit, t('Save')); 40 41 // Visit the system path for the node and confirm a cache entry is 42 // created. 43 cache_clear_all('*', 'cache_path', TRUE); 44 $this->drupalGet($edit['source']); 45 $this->assertTrue(cache_get($edit['source'], 'cache_path'), t('Cache entry was created.')); 46 47 // Visit the alias for the node and confirm a cache entry is created. 48 cache_clear_all('*', 'cache_path', TRUE); 49 $this->drupalGet($edit['alias']); 50 $this->assertTrue(cache_get($edit['source'], 'cache_path'), t('Cache entry was created.')); 51 } 52 53 /** 54 * Tests alias functionality through the admin interfaces. 55 */ 56 function testAdminAlias() { 57 // Create test node. 58 $node1 = $this->drupalCreateNode(); 59 60 // Create alias. 61 $edit = array(); 62 $edit['source'] = 'node/' . $node1->nid; 63 $edit['alias'] = $this->randomName(8); 64 $this->drupalPost('admin/config/search/path/add', $edit, t('Save')); 65 66 // Confirm that the alias works. 67 $this->drupalGet($edit['alias']); 68 $this->assertText($node1->title, 'Alias works.'); 69 $this->assertResponse(200); 70 71 // Change alias to one containing "exotic" characters. 72 $pid = $this->getPID($edit['alias']); 73 74 $previous = $edit['alias']; 75 $edit['alias'] = "- ._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters. 76 "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string. 77 "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets. 78 $this->drupalPost('admin/config/search/path/edit/' . $pid, $edit, t('Save')); 79 80 // Confirm that the alias works. 81 $this->drupalGet($edit['alias']); 82 $this->assertText($node1->title, 'Changed alias works.'); 83 $this->assertResponse(200); 84 85 drupal_static_reset('drupal_lookup_path'); 86 // Confirm that previous alias no longer works. 87 $this->drupalGet($previous); 88 $this->assertNoText($node1->title, 'Previous alias no longer works.'); 89 $this->assertResponse(404); 90 91 // Create second test node. 92 $node2 = $this->drupalCreateNode(); 93 94 // Set alias to second test node. 95 $edit['source'] = 'node/' . $node2->nid; 96 // leave $edit['alias'] the same 97 $this->drupalPost('admin/config/search/path/add', $edit, t('Save')); 98 99 // Confirm no duplicate was created. 100 $this->assertRaw(t('The alias %alias is already in use in this language.', array('%alias' => $edit['alias'])), 'Attempt to move alias was rejected.'); 101 102 // Delete alias. 103 $this->drupalPost('admin/config/search/path/edit/' . $pid, array(), t('Delete')); 104 $this->drupalPost(NULL, array(), t('Confirm')); 105 106 // Confirm that the alias no longer works. 107 $this->drupalGet($edit['alias']); 108 $this->assertNoText($node1->title, 'Alias was successfully deleted.'); 109 $this->assertResponse(404); 110 } 111 112 /** 113 * Tests alias functionality through the node interfaces. 114 */ 115 function testNodeAlias() { 116 // Create test node. 117 $node1 = $this->drupalCreateNode(); 118 119 // Create alias. 120 $edit = array(); 121 $edit['path[alias]'] = $this->randomName(8); 122 $this->drupalPost('node/' . $node1->nid . '/edit', $edit, t('Save')); 123 124 // Confirm that the alias works. 125 $this->drupalGet($edit['path[alias]']); 126 $this->assertText($node1->title, 'Alias works.'); 127 $this->assertResponse(200); 128 129 // Change alias to one containing "exotic" characters. 130 $previous = $edit['path[alias]']; 131 $edit['path[alias]'] = "- ._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters. 132 "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string. 133 "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets. 134 $this->drupalPost('node/' . $node1->nid . '/edit', $edit, t('Save')); 135 136 // Confirm that the alias works. 137 $this->drupalGet($edit['path[alias]']); 138 $this->assertText($node1->title, 'Changed alias works.'); 139 $this->assertResponse(200); 140 141 // Make sure that previous alias no longer works. 142 $this->drupalGet($previous); 143 $this->assertNoText($node1->title, 'Previous alias no longer works.'); 144 $this->assertResponse(404); 145 146 // Create second test node. 147 $node2 = $this->drupalCreateNode(); 148 149 // Set alias to second test node. 150 // Leave $edit['path[alias]'] the same. 151 $this->drupalPost('node/' . $node2->nid . '/edit', $edit, t('Save')); 152 153 // Confirm that the alias didn't make a duplicate. 154 $this->assertText(t('The alias is already in use.'), 'Attempt to moved alias was rejected.'); 155 156 // Delete alias. 157 $this->drupalPost('node/' . $node1->nid . '/edit', array('path[alias]' => ''), t('Save')); 158 159 // Confirm that the alias no longer works. 160 $this->drupalGet($edit['path[alias]']); 161 $this->assertNoText($node1->title, 'Alias was successfully deleted.'); 162 $this->assertResponse(404); 163 } 164 165 /** 166 * Returns the path ID. 167 * 168 * @param $alias 169 * A string containing an aliased path. 170 * 171 * @return int 172 * Integer representing the path ID. 173 */ 174 function getPID($alias) { 175 return db_query("SELECT pid FROM {url_alias} WHERE alias = :alias", array(':alias' => $alias))->fetchField(); 176 } 177 178 /** 179 * Tests that duplicate aliases fail validation. 180 */ 181 function testDuplicateNodeAlias() { 182 // Create one node with a random alias. 183 $node_one = $this->drupalCreateNode(); 184 $edit = array(); 185 $edit['path[alias]'] = $this->randomName(); 186 $this->drupalPost('node/' . $node_one->nid . '/edit', $edit, t('Save')); 187 188 // Now create another node and try to set the same alias. 189 $node_two = $this->drupalCreateNode(); 190 $this->drupalPost('node/' . $node_two->nid . '/edit', $edit, t('Save')); 191 $this->assertText(t('The alias is already in use.')); 192 $this->assertFieldByXPath("//input[@name='path[alias]' and contains(@class, 'error')]", $edit['path[alias]'], 'Textfield exists and has the error class.'); 193 } 194 } 195 196 /** 197 * Tests URL aliases for taxonomy terms. 198 */ 199 class PathTaxonomyTermTestCase extends DrupalWebTestCase { 200 public static function getInfo() { 201 return array( 202 'name' => 'Taxonomy term URL aliases', 203 'description' => 'Tests URL aliases for taxonomy terms.', 204 'group' => 'Path', 205 ); 206 } 207 208 function setUp() { 209 parent::setUp('path', 'taxonomy'); 210 211 // Create and login user. 212 $web_user = $this->drupalCreateUser(array('administer url aliases', 'administer taxonomy', 'access administration pages')); 213 $this->drupalLogin($web_user); 214 } 215 216 /** 217 * Tests alias functionality through the admin interfaces. 218 */ 219 function testTermAlias() { 220 // Create a term in the default 'Tags' vocabulary with URL alias. 221 $vocabulary = taxonomy_vocabulary_load(1); 222 $description = $this->randomName();; 223 $edit = array(); 224 $edit['name'] = $this->randomName(); 225 $edit['description[value]'] = $description; 226 $edit['path[alias]'] = $this->randomName(); 227 $this->drupalPost('admin/structure/taxonomy/' . $vocabulary->machine_name . '/add', $edit, t('Save')); 228 229 // Confirm that the alias works. 230 $this->drupalGet($edit['path[alias]']); 231 $this->assertText($description, 'Term can be accessed on URL alias.'); 232 233 // Change the term's URL alias. 234 $tid = db_query("SELECT tid FROM {taxonomy_term_data} WHERE name = :name", array(':name' => $edit['name']))->fetchField(); 235 $edit2 = array(); 236 $edit2['path[alias]'] = $this->randomName(); 237 $this->drupalPost('taxonomy/term/' . $tid . '/edit', $edit2, t('Save')); 238 239 // Confirm that the changed alias works. 240 $this->drupalGet($edit2['path[alias]']); 241 $this->assertText($description, 'Term can be accessed on changed URL alias.'); 242 243 // Confirm that the old alias no longer works. 244 $this->drupalGet($edit['path[alias]']); 245 $this->assertNoText($description, 'Old URL alias has been removed after altering.'); 246 $this->assertResponse(404, 'Old URL alias returns 404.'); 247 248 // Remove the term's URL alias. 249 $edit3 = array(); 250 $edit3['path[alias]'] = ''; 251 $this->drupalPost('taxonomy/term/' . $tid . '/edit', $edit3, t('Save')); 252 253 // Confirm that the alias no longer works. 254 $this->drupalGet($edit2['path[alias]']); 255 $this->assertNoText($description, 'Old URL alias has been removed after altering.'); 256 $this->assertResponse(404, 'Old URL alias returns 404.'); 257 } 258 } 259 260 /** 261 * Tests URL aliases for translated nodes. 262 */ 263 class PathLanguageTestCase extends DrupalWebTestCase { 264 public static function getInfo() { 265 return array( 266 'name' => 'Path aliases with translated nodes', 267 'description' => 'Confirm that paths work with translated nodes', 268 'group' => 'Path', 269 ); 270 } 271 272 function setUp() { 273 parent::setUp('path', 'locale', 'translation'); 274 275 // Create and login user. 276 $this->web_user = $this->drupalCreateUser(array('edit any page content', 'create page content', 'administer url aliases', 'create url aliases', 'administer languages', 'translate content', 'access administration pages')); 277 $this->drupalLogin($this->web_user); 278 279 // Enable French language. 280 $edit = array(); 281 $edit['langcode'] = 'fr'; 282 283 $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); 284 285 // Enable URL language detection and selection. 286 $edit = array('language[enabled][locale-url]' => 1); 287 $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings')); 288 } 289 290 /** 291 * Test alias functionality through the admin interfaces. 292 */ 293 function testAliasTranslation() { 294 // Set 'page' content type to enable translation. 295 variable_set('language_content_type_page', 2); 296 297 $english_node = $this->drupalCreateNode(array('type' => 'page')); 298 $english_alias = $this->randomName(); 299 300 // Edit the node to set language and path. 301 $edit = array(); 302 $edit['language'] = 'en'; 303 $edit['path[alias]'] = $english_alias; 304 $this->drupalPost('node/' . $english_node->nid . '/edit', $edit, t('Save')); 305 306 // Confirm that the alias works. 307 $this->drupalGet($english_alias); 308 $this->assertText($english_node->title, 'Alias works.'); 309 310 // Translate the node into French. 311 $this->drupalGet('node/' . $english_node->nid . '/translate'); 312 $this->clickLink(t('add translation')); 313 $edit = array(); 314 $langcode = LANGUAGE_NONE; 315 $edit["title"] = $this->randomName(); 316 $edit["body[$langcode][0][value]"] = $this->randomName(); 317 $french_alias = $this->randomName(); 318 $edit['path[alias]'] = $french_alias; 319 $this->drupalPost(NULL, $edit, t('Save')); 320 321 // Clear the path lookup cache. 322 drupal_lookup_path('wipe'); 323 324 // Ensure the node was created. 325 $french_node = $this->drupalGetNodeByTitle($edit["title"]); 326 $this->assertTrue(($french_node), 'Node found in database.'); 327 328 // Confirm that the alias works. 329 $this->drupalGet('fr/' . $edit['path[alias]']); 330 $this->assertText($french_node->title, 'Alias for French translation works.'); 331 332 // Confirm that the alias is returned by url(). 333 drupal_static_reset('language_list'); 334 drupal_static_reset('locale_url_outbound_alter'); 335 $languages = language_list(); 336 $url = url('node/' . $french_node->nid, array('language' => $languages[$french_node->language])); 337 $this->assertTrue(strpos($url, $edit['path[alias]']), t('URL contains the path alias.')); 338 339 // Confirm that the alias works even when changing language negotiation 340 // options. Enable User language detection and selection over URL one. 341 $edit = array( 342 'language[enabled][locale-user]' => 1, 343 'language[weight][locale-user]' => -9, 344 'language[enabled][locale-url]' => 1, 345 'language[weight][locale-url]' => -8, 346 ); 347 $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings')); 348 349 // Change user language preference. 350 $edit = array('language' => 'fr'); 351 $this->drupalPost("user/{$this->web_user->uid}/edit", $edit, t('Save')); 352 353 // Check that the English alias works. In this situation French is the 354 // current UI and content language, while URL language is English (since we 355 // do not have a path prefix we fall back to the site's default language). 356 // We need to ensure that the user language preference is not taken into 357 // account while determining the path alias language, because if this 358 // happens we have no way to check that the path alias is valid: there is no 359 // path alias for French matching the english alias. So drupal_lookup_path() 360 // needs to use the URL language to check whether the alias is valid. 361 $this->drupalGet($english_alias); 362 $this->assertText($english_node->title, 'Alias for English translation works.'); 363 364 // Check that the French alias works. 365 $this->drupalGet("fr/$french_alias"); 366 $this->assertText($french_node->title, 'Alias for French translation works.'); 367 368 // Disable URL language negotiation. 369 $edit = array('language[enabled][locale-url]' => FALSE); 370 $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings')); 371 372 // Check that the English alias still works. 373 $this->drupalGet($english_alias); 374 $this->assertText($english_node->title, 'Alias for English translation works.'); 375 376 // Check that the French alias is not available. We check the unprefixed 377 // alias because we disabled URL language negotiation above. In this 378 // situation only aliases in the default language and language neutral ones 379 // should keep working. 380 $this->drupalGet($french_alias); 381 $this->assertResponse(404, t('Alias for French translation is unavailable when URL language negotiation is disabled.')); 382 383 // drupal_lookup_path() has an internal static cache. Check to see that 384 // it has the appropriate contents at this point. 385 drupal_lookup_path('wipe'); 386 $french_node_path = drupal_lookup_path('source', $french_alias, $french_node->language); 387 $this->assertEqual($french_node_path, 'node/' . $french_node->nid, t('Normal path works.')); 388 // Second call should return the same path. 389 $french_node_path = drupal_lookup_path('source', $french_alias, $french_node->language); 390 $this->assertEqual($french_node_path, 'node/' . $french_node->nid, t('Normal path is the same.')); 391 392 // Confirm that the alias works. 393 $french_node_alias = drupal_lookup_path('alias', 'node/' . $french_node->nid, $french_node->language); 394 $this->assertEqual($french_node_alias, $french_alias, t('Alias works.')); 395 // Second call should return the same alias. 396 $french_node_alias = drupal_lookup_path('alias', 'node/' . $french_node->nid, $french_node->language); 397 $this->assertEqual($french_node_alias, $french_alias, t('Alias is the same.')); 398 } 399 } 400 401 /** 402 * Tests the user interface for creating path aliases, with languages. 403 */ 404 class PathLanguageUITestCase extends DrupalWebTestCase { 405 public static function getInfo() { 406 return array( 407 'name' => 'Path aliases with languages', 408 'description' => 'Confirm that the Path module user interface works with languages.', 409 'group' => 'Path', 410 ); 411 } 412 413 function setUp() { 414 parent::setUp('path', 'locale'); 415 416 // Create and login user. 417 $web_user = $this->drupalCreateUser(array('edit any page content', 'create page content', 'administer url aliases', 'create url aliases', 'administer languages', 'access administration pages')); 418 $this->drupalLogin($web_user); 419 420 // Enable French language. 421 $edit = array(); 422 $edit['langcode'] = 'fr'; 423 424 $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); 425 426 // Enable URL language detection and selection. 427 $edit = array('language[enabled][locale-url]' => 1); 428 $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings')); 429 } 430 431 /** 432 * Tests that a language-neutral URL alias works. 433 */ 434 function testLanguageNeutralURLs() { 435 $name = $this->randomName(8); 436 $edit = array(); 437 $edit['source'] = 'admin/config/search/path'; 438 $edit['alias'] = $name; 439 $this->drupalPost('admin/config/search/path/add', $edit, t('Save')); 440 441 $this->drupalGet($name); 442 $this->assertText(t('Filter aliases'), 'Language-neutral URL alias works'); 443 } 444 445 /** 446 * Tests that a default language URL alias works. 447 */ 448 function testDefaultLanguageURLs() { 449 $name = $this->randomName(8); 450 $edit = array(); 451 $edit['source'] = 'admin/config/search/path'; 452 $edit['alias'] = $name; 453 $edit['language'] = 'en'; 454 $this->drupalPost('admin/config/search/path/add', $edit, t('Save')); 455 456 $this->drupalGet($name); 457 $this->assertText(t('Filter aliases'), 'English URL alias works'); 458 } 459 460 /** 461 * Tests that a non-default language URL alias works. 462 */ 463 function testNonDefaultURLs() { 464 $name = $this->randomName(8); 465 $edit = array(); 466 $edit['source'] = 'admin/config/search/path'; 467 $edit['alias'] = $name; 468 $edit['language'] = 'fr'; 469 $this->drupalPost('admin/config/search/path/add', $edit, t('Save')); 470 471 $this->drupalGet('fr/' . $name); 472 $this->assertText(t('Filter aliases'), 'Foreign URL alias works'); 473 } 474 475 } 476 477 /** 478 * Tests that paths are not prefixed on a monolingual site. 479 */ 480 class PathMonolingualTestCase extends DrupalWebTestCase { 481 public static function getInfo() { 482 return array( 483 'name' => 'Paths on non-English monolingual sites', 484 'description' => 'Confirm that paths are not changed on monolingual non-English sites', 485 'group' => 'Path', 486 ); 487 } 488 489 function setUp() { 490 global $language; 491 parent::setUp('path', 'locale', 'translation'); 492 493 // Create and login user. 494 $web_user = $this->drupalCreateUser(array('administer languages', 'access administration pages')); 495 $this->drupalLogin($web_user); 496 497 // Enable French language. 498 $edit = array(); 499 $edit['langcode'] = 'fr'; 500 $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); 501 502 // Make French the default language. 503 $edit = array('site_default' => 'fr'); 504 $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration')); 505 506 // Disable English. 507 $edit = array('enabled[en]' => FALSE); 508 $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration')); 509 510 // Verify that French is the only language. 511 $this->assertFalse(drupal_multilingual(), t('Site is mono-lingual')); 512 $this->assertEqual(language_default('language'), 'fr', t('French is the default language')); 513 514 // Set language detection to URL. 515 $edit = array('language[enabled][locale-url]' => TRUE); 516 $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings')); 517 518 // Force languages to be initialized. 519 drupal_language_initialize(); 520 } 521 522 /** 523 * Verifies that links do not have language prefixes in them. 524 */ 525 function testPageLinks() { 526 // Navigate to 'admin/config' path. 527 $this->drupalGet('admin/config'); 528 529 // Verify that links in this page do not have a 'fr/' prefix. 530 $this->assertNoLinkByHref('/fr/', 'Links do not contain language prefix'); 531 532 // Verify that links in this page can be followed and work. 533 $this->clickLink(t('Languages')); 534 $this->assertResponse(200, 'Clicked link results in a valid page'); 535 $this->assertText(t('Add language'), 'Page contains the add language text'); 536 } 537 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
title