path.test 18.9 KB
Newer Older
1 2
<?php

3 4
/**
 * @file
5
 * Tests for path.module.
6 7
 */

8
class PathTestCase extends DrupalWebTestCase {
9
  public static function getInfo() {
10
    return array(
11 12 13
      'name' => 'Path alias functionality',
      'description' => 'Add, edit, delete, and change alias and verify its consistency in the database.',
      'group' => 'Path',
14 15 16 17 18
    );
  }

  function setUp() {
    parent::setUp('path');
19 20 21

    // Create test user and login.
    $web_user = $this->drupalCreateUser(array('create page content', 'edit own page content', 'administer url aliases', 'create url aliases'));
22 23 24
    $this->drupalLogin($web_user);
  }

25 26 27 28 29 30 31 32 33
  /**
   * Test the path cache.
   */
  function testPathCache() {
    // Create test node.
    $node1 = $this->drupalCreateNode();

    // Create alias.
    $edit = array();
34 35
    $edit['source'] = 'node/' . $node1->nid;
    $edit['alias'] = $this->randomName(8);
36
    $this->drupalPost('admin/config/search/path/add', $edit, t('Save'));
37 38 39

    // Visit the system path for the node and confirm a cache entry is
    // created.
40
    cache('path')->flush();
41
    $this->drupalGet($edit['source']);
42
    $this->assertTrue(cache('path')->get($edit['source']), t('Cache entry was created.'));
43 44

    // Visit the alias for the node and confirm a cache entry is created.
45
    cache('path')->flush();
46
    $this->drupalGet($edit['alias']);
47
    $this->assertTrue(cache('path')->get($edit['source']), t('Cache entry was created.'));
48 49
  }

50 51 52 53
  /**
   * Test alias functionality through the admin interfaces.
   */
  function testAdminAlias() {
54
    // Create test node.
55
    $node1 = $this->drupalCreateNode();
56

57
    // Create alias.
58
    $edit = array();
59 60
    $edit['source'] = 'node/' . $node1->nid;
    $edit['alias'] = $this->randomName(8);
61
    $this->drupalPost('admin/config/search/path/add', $edit, t('Save'));
62

63
    // Confirm that the alias works.
64
    $this->drupalGet($edit['alias']);
65
    $this->assertText($node1->title, 'Alias works.');
66
    $this->assertResponse(200);
67

68
    // Change alias to one containing "exotic" characters.
69
    $pid = $this->getPID($edit['alias']);
70

71
    $previous = $edit['alias'];
72 73 74
    $edit['alias'] = "- ._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters.
      "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string.
      "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets.
75
    $this->drupalPost('admin/config/search/path/edit/' . $pid, $edit, t('Save'));
76

77
    // Confirm that the alias works.
78
    $this->drupalGet($edit['alias']);
79
    $this->assertText($node1->title, 'Changed alias works.');
80
    $this->assertResponse(200);
81

82
    drupal_static_reset('drupal_lookup_path');
83
    // Confirm that previous alias no longer works.
84 85 86 87
    $this->drupalGet($previous);
    $this->assertNoText($node1->title, 'Previous alias no longer works.');
    $this->assertResponse(404);

88
    // Create second test node.
89
    $node2 = $this->drupalCreateNode();
90

91
    // Set alias to second test node.
92 93
    $edit['source'] = 'node/' . $node2->nid;
    // leave $edit['alias'] the same
94
    $this->drupalPost('admin/config/search/path/add', $edit, t('Save'));
95

96
    // Confirm no duplicate was created.
97
    $this->assertRaw(t('The alias %alias is already in use in this language.', array('%alias' => $edit['alias'])), 'Attempt to move alias was rejected.');
98

99
    // Delete alias.
100 101
    $this->drupalPost('admin/config/search/path/edit/' . $pid, array(), t('Delete'));
    $this->drupalPost(NULL, array(), t('Confirm'));
102

103
    // Confirm that the alias no longer works.
104
    $this->drupalGet($edit['alias']);
105
    $this->assertNoText($node1->title, 'Alias was successfully deleted.');
106
    $this->assertResponse(404);
107 108 109 110 111 112
  }

  /**
   * Test alias functionality through the node interfaces.
   */
  function testNodeAlias() {
113
    // Create test node.
114
    $node1 = $this->drupalCreateNode();
115

116
    // Create alias.
117
    $edit = array();
118
    $edit['path[alias]'] = $this->randomName(8);
119 120
    $this->drupalPost('node/' . $node1->nid . '/edit', $edit, t('Save'));

121
    // Confirm that the alias works.
122
    $this->drupalGet($edit['path[alias]']);
123
    $this->assertText($node1->title, 'Alias works.');
124
    $this->assertResponse(200);
125

126
    // Change alias to one containing "exotic" characters.
127
    $previous = $edit['path[alias]'];
128 129 130
    $edit['path[alias]'] = "- ._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters.
      "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string.
      "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets.
131 132
    $this->drupalPost('node/' . $node1->nid . '/edit', $edit, t('Save'));

133
    // Confirm that the alias works.
134
    $this->drupalGet($edit['path[alias]']);
135
    $this->assertText($node1->title, 'Changed alias works.');
136
    $this->assertResponse(200);
137

138
    // Make sure that previous alias no longer works.
139
    $this->drupalGet($previous);
140
    $this->assertNoText($node1->title, 'Previous alias no longer works.');
141 142
    $this->assertResponse(404);

143
    // Create second test node.
144
    $node2 = $this->drupalCreateNode();
145

146
    // Set alias to second test node.
147
    // Leave $edit['path[alias]'] the same.
148 149
    $this->drupalPost('node/' . $node2->nid . '/edit', $edit, t('Save'));

150
    // Confirm that the alias didn't make a duplicate.
151
    $this->assertText(t('The alias is already in use.'), 'Attempt to moved alias was rejected.');
152

153
    // Delete alias.
154
    $this->drupalPost('node/' . $node1->nid . '/edit', array('path[alias]' => ''), t('Save'));
155

156
    // Confirm that the alias no longer works.
157
    $this->drupalGet($edit['path[alias]']);
158
    $this->assertNoText($node1->title, 'Alias was successfully deleted.');
159
    $this->assertResponse(404);
160 161
  }

162 163
  function getPID($alias) {
    return db_query("SELECT pid FROM {url_alias} WHERE alias = :alias", array(':alias' => $alias))->fetchField();
164 165
  }
}
166

167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
/**
 * Test URL aliases for taxonomy terms.
 */
class PathTaxonomyTermTestCase extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Taxonomy term URL aliases',
      'description' => 'Tests URL aliases for taxonomy terms.',
      'group' => 'Path',
    );
  }

  function setUp() {
    parent::setUp('path', 'taxonomy');

    // Create and login user.
    $web_user = $this->drupalCreateUser(array('administer url aliases', 'administer taxonomy', 'access administration pages'));
    $this->drupalLogin($web_user);
  }

  /**
   * Test alias functionality through the admin interfaces.
   */
  function testTermAlias() {
    // Create a term in the default 'Tags' vocabulary with URL alias.
192
    $vocabulary = taxonomy_vocabulary_load(1);
193
    $description = $this->randomName();;
194 195
    $edit = array();
    $edit['name'] = $this->randomName();
196
    $edit['description[value]'] = $description;
197
    $edit['path[alias]'] = $this->randomName();
198
    $this->drupalPost('admin/structure/taxonomy/' . $vocabulary->machine_name . '/add', $edit, t('Save'));
199 200 201

    // Confirm that the alias works.
    $this->drupalGet($edit['path[alias]']);
202
    $this->assertText($description, 'Term can be accessed on URL alias.');
203 204 205 206 207 208 209 210 211

    // Change the term's URL alias.
    $tid = db_query("SELECT tid FROM {taxonomy_term_data} WHERE name = :name", array(':name' => $edit['name']))->fetchField();
    $edit2 = array();
    $edit2['path[alias]'] = $this->randomName();
    $this->drupalPost('taxonomy/term/' . $tid . '/edit', $edit2, t('Save'));

    // Confirm that the changed alias works.
    $this->drupalGet($edit2['path[alias]']);
212
    $this->assertText($description, 'Term can be accessed on changed URL alias.');
213 214 215

    // Confirm that the old alias no longer works.
    $this->drupalGet($edit['path[alias]']);
216
    $this->assertNoText($description, 'Old URL alias has been removed after altering.');
217 218 219 220 221 222 223 224 225
    $this->assertResponse(404, 'Old URL alias returns 404.');

    // Remove the term's URL alias.
    $edit3 = array();
    $edit3['path[alias]'] = '';
    $this->drupalPost('taxonomy/term/' . $tid . '/edit', $edit3, t('Save'));

    // Confirm that the alias no longer works.
    $this->drupalGet($edit2['path[alias]']);
226
    $this->assertNoText($description, 'Old URL alias has been removed after altering.');
227 228 229 230
    $this->assertResponse(404, 'Old URL alias returns 404.');
  }
}

231
class PathLanguageTestCase extends DrupalWebTestCase {
232
  public static function getInfo() {
233
    return array(
234 235 236
      'name' => 'Path aliases with translated nodes',
      'description' => 'Confirm that paths work with translated nodes',
      'group' => 'Path',
237 238 239 240 241 242 243
    );
  }

  function setUp() {
    parent::setUp('path', 'locale', 'translation');

    // Create and login user.
244 245
    $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'));
    $this->drupalLogin($this->web_user);
246 247 248

    // Enable French language.
    $edit = array();
249
    $edit['predefined_langcode'] = 'fr';
250

251
    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
252

253
    // Enable URL language detection and selection.
254
    $edit = array('language_interface[enabled][locale-url]' => 1);
255
    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
256 257 258 259 260 261 262
  }

  /**
   * Test alias functionality through the admin interfaces.
   */
  function testAliasTranslation() {
    // Set 'page' content type to enable translation.
263
    variable_set('node_type_language_page', TRANSLATION_ENABLED);
264

265
    $english_node = $this->drupalCreateNode(array('type' => 'page'));
266
    $english_alias = $this->randomName();
267 268

    // Edit the node to set language and path.
269
    $edit = array();
270
    $edit['langcode'] = 'en';
271
    $edit['path[alias]'] = $english_alias;
272
    $this->drupalPost('node/' . $english_node->nid . '/edit', $edit, t('Save'));
273 274

    // Confirm that the alias works.
275
    $this->drupalGet($english_alias);
276
    $this->assertText($english_node->title, 'Alias works.');
277 278 279 280 281

    // Translate the node into French.
    $this->drupalGet('node/' . $english_node->nid . '/translate');
    $this->clickLink(t('add translation'));
    $edit = array();
282
    $langcode = LANGUAGE_NONE;
283
    $edit["title"] = $this->randomName();
284
    $edit["body[$langcode][0][value]"] = $this->randomName();
285 286
    $french_alias = $this->randomName();
    $edit['path[alias]'] = $french_alias;
287 288 289 290 291 292
    $this->drupalPost(NULL, $edit, t('Save'));

    // Clear the path lookup cache.
    drupal_lookup_path('wipe');

    // Ensure the node was created.
293
    $french_node = $this->drupalGetNodeByTitle($edit["title"]);
294 295 296
    $this->assertTrue(($french_node), 'Node found in database.');

    // Confirm that the alias works.
297
    $this->drupalGet('fr/' . $edit['path[alias]']);
298
    $this->assertText($french_node->title, 'Alias for French translation works.');
299

300 301
    // Confirm that the alias is returned by url(). Languages are cached on
    // many levels, and we need to clear those caches.
302
    drupal_static_reset('language_list');
303
    drupal_static_reset('locale_url_outbound_alter');
304
    drupal_static_reset('locale_language_url_rewrite_url');
305
    $languages = language_list();
306
    $url = url('node/' . $french_node->nid, array('language' => $languages[$french_node->langcode]));
307
    $this->assertTrue(strpos($url, $edit['path[alias]']), t('URL contains the path alias.'));
308 309 310 311

    // Confirm that the alias works even when changing language negotiation
    // options. Enable User language detection and selection over URL one.
    $edit = array(
312 313 314 315
      'language_interface[enabled][locale-user]' => 1,
      'language_interface[weight][locale-user]' => -9,
      'language_interface[enabled][locale-url]' => 1,
      'language_interface[weight][locale-url]' => -8,
316
    );
317
    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

    // Change user language preference.
    $edit = array('language' => 'fr');
    $this->drupalPost("user/{$this->web_user->uid}/edit", $edit, t('Save'));

    // Check that the English alias works. In this situation French is the
    // current UI and content language, while URL language is English (since we
    // do not have a path prefix we fall back to the site's default language).
    // We need to ensure that the user language preference is not taken into
    // account while determining the path alias language, because if this
    // happens we have no way to check that the path alias is valid: there is no
    // path alias for French matching the english alias. So drupal_lookup_path()
    // needs to use the URL language to check whether the alias is valid.
    $this->drupalGet($english_alias);
    $this->assertText($english_node->title, 'Alias for English translation works.');

    // Check that the French alias works.
    $this->drupalGet("fr/$french_alias");
    $this->assertText($french_node->title, 'Alias for French translation works.');

    // Disable URL language negotiation.
339
    $edit = array('language_interface[enabled][locale-url]' => FALSE);
340
    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
341 342 343 344 345 346 347 348 349 350

    // Check that the English alias still works.
    $this->drupalGet($english_alias);
    $this->assertText($english_node->title, 'Alias for English translation works.');

    // Check that the French alias is not available. We check the unprefixed
    // alias because we disabled URL language negotiation above. In this
    // situation only aliases in the default language and language neutral ones
    // should keep working.
    $this->drupalGet($french_alias);
351
    $this->assertResponse(404, t('Alias for French translation is unavailable when URL language negotiation is disabled.'));
352 353 354 355

    // drupal_lookup_path() has an internal static cache. Check to see that
    // it has the appropriate contents at this point.
    drupal_lookup_path('wipe');
356
    $french_node_path = drupal_lookup_path('source', $french_alias, $french_node->langcode);
357
    $this->assertEqual($french_node_path, 'node/' . $french_node->nid, t('Normal path works.'));
358
    // Second call should return the same path.
359
    $french_node_path = drupal_lookup_path('source', $french_alias, $french_node->langcode);
360
    $this->assertEqual($french_node_path, 'node/' . $french_node->nid, t('Normal path is the same.'));
361 362

    // Confirm that the alias works.
363
    $french_node_alias = drupal_lookup_path('alias', 'node/' . $french_node->nid, $french_node->langcode);
364
    $this->assertEqual($french_node_alias, $french_alias, t('Alias works.'));
365
    // Second call should return the same alias.
366
    $french_node_alias = drupal_lookup_path('alias', 'node/' . $french_node->nid, $french_node->langcode);
367
    $this->assertEqual($french_node_alias, $french_alias, t('Alias is the same.'));
368 369
  }
}
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391

/**
 * Tests the user interface for creating path aliases, with languages.
 */
class PathLanguageUITestCase extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Path aliases with languages',
      'description' => 'Confirm that the Path module user interface works with languages.',
      'group' => 'Path',
    );
  }

  function setUp() {
    parent::setUp('path', 'locale');

    // Create and login user.
    $web_user = $this->drupalCreateUser(array('edit any page content', 'create page content', 'administer url aliases', 'create url aliases', 'administer languages', 'access administration pages'));
    $this->drupalLogin($web_user);

    // Enable French language.
    $edit = array();
392
    $edit['predefined_langcode'] = 'fr';
393 394 395

    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));

396
    // Enable URL language detection and selection.
397
    $edit = array('language_interface[enabled][locale-url]' => 1);
398
    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
  }

  /**
   * Tests that a language-neutral URL alias works.
   */
  function testLanguageNeutralURLs() {
    $name = $this->randomName(8);
    $edit = array();
    $edit['source'] = 'admin/config/search/path';
    $edit['alias'] = $name;
    $this->drupalPost('admin/config/search/path/add', $edit, t('Save'));

    $this->drupalGet($name);
    $this->assertText(t('Filter aliases'), 'Language-neutral URL alias works');
  }

  /**
   * Tests that a default language URL alias works.
   */
  function testDefaultLanguageURLs() {
    $name = $this->randomName(8);
    $edit = array();
    $edit['source'] = 'admin/config/search/path';
    $edit['alias'] = $name;
423
    $edit['langcode'] = 'en';
424 425 426 427 428 429 430 431 432 433 434 435 436 437
    $this->drupalPost('admin/config/search/path/add', $edit, t('Save'));

    $this->drupalGet($name);
    $this->assertText(t('Filter aliases'), 'English URL alias works');
  }

  /**
   * Tests that a non-default language URL alias works.
   */
  function testNonDefaultURLs() {
    $name = $this->randomName(8);
    $edit = array();
    $edit['source'] = 'admin/config/search/path';
    $edit['alias'] = $name;
438
    $edit['langcode'] = 'fr';
439 440 441 442 443 444 445
    $this->drupalPost('admin/config/search/path/add', $edit, t('Save'));

    $this->drupalGet('fr/' . $name);
    $this->assertText(t('Filter aliases'), 'Foreign URL alias works');
  }

}
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467

/**
 * Tests that paths are not prefixed on a monolingual site.
 */
class PathMonolingualTestCase extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Paths on non-English monolingual sites',
      'description' => 'Confirm that paths are not changed on monolingual non-English sites',
      'group' => 'Path',
    );
  }

  function setUp() {
    parent::setUp('path', 'locale', 'translation');

    // Create and login user.
    $web_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
    $this->drupalLogin($web_user);

    // Enable French language.
    $edit = array();
468
    $edit['predefined_langcode'] = 'fr';
469 470 471 472 473 474 475
    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));

    // Make French the default language.
    $edit = array('site_default' => 'fr');
    $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));

    // Disable English.
476
    $edit = array('languages[en][enabled]' => FALSE);
477 478 479
    $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));

    // Verify that French is the only language.
480
    $this->assertFalse(language_multilingual(), t('Site is mono-lingual'));
481
    $this->assertEqual(language_default()->langcode, 'fr', t('French is the default language'));
482 483

    // Set language detection to URL.
484
    $edit = array('language_interface[enabled][locale-url]' => TRUE);
485
    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506

    // Force languages to be initialized.
    drupal_language_initialize();
  }

  /**
   * Verifies that links do not have language prefixes in them.
   */
  function testPageLinks() {
    // Navigate to 'admin/config' path.
    $this->drupalGet('admin/config');

    // Verify that links in this page do not have a 'fr/' prefix.
    $this->assertNoLinkByHref('/fr/', 'Links do not contain language prefix');

    // Verify that links in this page can be followed and work.
    $this->clickLink(t('Languages'));
    $this->assertResponse(200, 'Clicked link results in a valid page');
    $this->assertText(t('Add language'), 'Page contains the add language text');
  }
}