system.test 72.1 KB
Newer Older
1 2 3
<?php
// $Id$

4 5 6 7
/**
 * Helper class for module test cases.
 */
class ModuleTestCase extends DrupalWebTestCase {
8 9
  protected $admin_user;

10 11 12
  function setUp() {
    parent::setUp('system_test');

13
    $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer modules'));
14 15 16
    $this->drupalLogin($this->admin_user);
  }

17
  /**
18 19 20 21 22 23 24
   * Assert there are tables that begin with the specified base table name.
   *
   * @param $base_table
   *   Beginning of table name to look for.
   * @param $count
   *   (optional) Whether or not to assert that there are tables that match the
   *   specified base table. Defaults to TRUE.
25
   */
26
  function assertTableCount($base_table, $count = TRUE) {
27
    $tables = db_find_tables($base_table . '%');
28 29 30 31 32

    if ($count) {
      return $this->assertTrue($tables, t('Tables matching "@base_table" found.', array('@base_table' => $base_table)));
    }
    return $this->assertFalse($tables, t('Tables matching "@base_table" not found.', array('@base_table' => $base_table)));
33 34 35
  }

  /**
36 37 38 39 40 41
   * Assert the list of modules are enabled or disabled.
   *
   * @param $modules
   *   Module list to check.
   * @param $enabled
   *   Expected module state.
42
   */
43 44 45 46 47 48 49 50 51 52 53 54
  function assertModules(array $modules, $enabled) {
    module_list(TRUE);
    foreach ($modules as $module) {
      if ($enabled) {
        $message = 'Module "@module" is enabled.';
      }
      else {
        $message = 'Module "@module" is not enabled.';
      }
      $this->assertEqual(module_exists($module), $enabled, t($message, array('@module' => $module)));
    }
  }
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

  /**
   * Verify a log entry was entered for a module's status change.
   * Called in the same way of the expected original watchdog() execution.
   *
   * @param $type
   *   The category to which this message belongs.
   * @param $message
   *   The message to store in the log. Keep $message translatable
   *   by not concatenating dynamic values into it! Variables in the
   *   message should be added by using placeholder strings alongside
   *   the variables argument to declare the value of the placeholders.
   *   See t() for documentation on how $message and $variables interact.
   * @param $variables
   *   Array of variables to replace in the message on display or
   *   NULL if message is already translated or not possible to
   *   translate.
   * @param $severity
   *   The severity of the message, as per RFC 3164.
   * @param $link
   *   A link to associate with the message.
   */
  function assertLogMessage($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = '') {
    $count = db_select('watchdog', 'w')
      ->condition('type', $type)
      ->condition('message', $message)
      ->condition('variables', serialize($variables))
      ->condition('severity', $severity)
      ->condition('link', $link)
      ->countQuery()
      ->execute()
      ->fetchField();
    $this->assertTrue($count > 0, t('watchdog table contains @count rows for @message', array('@count' => $count, '@message' => $message)));
  }
89
}
90

91 92 93 94
/**
 * Test module enabling/disabling functionality.
 */
class EnableDisableTestCase extends ModuleTestCase {
95
  public static function getInfo() {
96
    return array(
97 98 99
      'name' => 'Enable/disable modules',
      'description' => 'Enable/disable core module and confirm table creation/deletion.',
      'group' => 'Module',
100
    );
101 102 103 104
  }

  /**
   * Enable a module, check the database for related tables, disable module,
105
   * check for related tables, uninstall module, check for related tables.
106
   * Also check for invocation of the hook_module_action hook.
107 108 109 110 111 112
   */
  function testEnableDisable() {
    // Enable aggregator, and check tables.
    $this->assertModules(array('aggregator'), FALSE);
    $this->assertTableCount('aggregator', FALSE);

113
    // Install (and enable) aggregator module.
114
    $edit = array();
115
    $edit['modules[Core][aggregator][enable]'] = 'aggregator';
116
    $edit['modules[Core][forum][enable]'] = 'forum';
117
    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
118 119
    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));

120 121 122
    // Check that hook_modules_installed and hook_modules_enabled hooks were invoked and check tables.
    $this->assertText(t('hook_modules_installed fired for aggregator'), t('hook_modules_installed fired.'));
    $this->assertText(t('hook_modules_enabled fired for aggregator'), t('hook_modules_enabled fired.'));
123 124
    $this->assertModules(array('aggregator'), TRUE);
    $this->assertTableCount('aggregator', TRUE);
125
    $this->assertLogMessage('system', "%module module installed.", array('%module' => 'aggregator'), WATCHDOG_INFO);
126
    $this->assertLogMessage('system', "%module module enabled.", array('%module' => 'aggregator'), WATCHDOG_INFO);
127 128 129

    // Disable aggregator, check tables, uninstall aggregator, check tables.
    $edit = array();
130
    $edit['modules[Core][aggregator][enable]'] = FALSE;
131
    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
132 133
    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));

134 135
    // Check that hook_modules_disabled hook was invoked and check tables.
    $this->assertText(t('hook_modules_disabled fired for aggregator'), t('hook_modules_disabled fired.'));
136 137
    $this->assertModules(array('aggregator'), FALSE);
    $this->assertTableCount('aggregator', TRUE);
138
    $this->assertLogMessage('system', "%module module disabled.", array('%module' => 'aggregator'), WATCHDOG_INFO);
139

140
    // Uninstall the module.
141 142
    $edit = array();
    $edit['uninstall[aggregator]'] = 'aggregator';
143
    $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
144 145 146 147

    $this->drupalPost(NULL, NULL, t('Uninstall'));
    $this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.'));

148 149
    // Check that hook_modules_uninstalled hook was invoked and check tables.
    $this->assertText(t('hook_modules_uninstalled fired for aggregator'), t('hook_modules_uninstalled fired.'));
150 151
    $this->assertModules(array('aggregator'), FALSE);
    $this->assertTableCount('aggregator', FALSE);
152
    $this->assertLogMessage('system', "%module module uninstalled.", array('%module' => 'aggregator'), WATCHDOG_INFO);
153 154 155 156

    // Reinstall (and enable) aggregator module.
    $edit = array();
    $edit['modules[Core][aggregator][enable]'] = 'aggregator';
157
    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
158
    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
159
  }
160 161 162 163 164 165 166 167 168 169

  /**
   * Tests entity cache after enabling a module with a dependency on an enitity
   * providing module.
   */
  function testEntityCache() {
    module_enable(array('entity_cache_test'));
    $info = variable_get('entity_cache_test');
    $this->assertNotNull($info, t('Entity information must not be NULL'));
  }
170 171
}

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
/**
 * Tests failure of hook_requirements('install').
 */
class HookRequirementsTestCase extends ModuleTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Requirements hook failure',
      'description' => "Attempts enabling a module that fails hook_requirements('install').",
      'group' => 'Module',
    );
  }

  /**
   * Assert that a module cannot be installed if it fails hook_requirements().
   */
  function testHookRequirementsFailure() {
    $this->assertModules(array('requirements1_test'), FALSE);

    // Attempt to install the requirements1_test module.
    $edit = array();
    $edit['modules[Core][requirements1_test][enable]'] = 'requirements1_test';
    $this->drupalPost('admin/modules', $edit, t('Save configuration'));

    // Makes sure the module was NOT installed.
    $this->assertText(t('Requirements 1 Test failed requirements'), t('Modules status has been updated.'));
    $this->assertModules(array('requirements1_test'), FALSE);
  }
}

201 202 203 204
/**
 * Test module dependency functionality.
 */
class ModuleDependencyTestCase extends ModuleTestCase {
205
  public static function getInfo() {
206
    return array(
207 208 209
      'name' => 'Module dependencies',
      'description' => 'Enable module without dependency enabled.',
      'group' => 'Module',
210 211
    );
  }
212 213 214 215

  /**
   * Attempt to enable translation module without locale enabled.
   */
216
  function testEnableWithoutDependency() {
217 218
    // Attempt to enable content translation without locale enabled.
    $edit = array();
219
    $edit['modules[Core][translation][enable]'] = 'translation';
220
    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
    $this->assertText(t('Some required modules must be enabled'), t('Dependecy required.'));

    $this->assertModules(array('translation', 'locale'), FALSE);

    // Assert that the locale tables weren't enabled.
    $this->assertTableCount('languages', FALSE);
    $this->assertTableCount('locale', FALSE);

    $this->drupalPost(NULL, NULL, t('Continue'));
    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));

    $this->assertModules(array('translation', 'locale'), TRUE);

    // Assert that the locale tables were enabled.
    $this->assertTableCount('languages', TRUE);
    $this->assertTableCount('locale', TRUE);
  }
238 239 240 241 242 243 244

  /**
   * Attempt to enable a module with a missing dependency.
   */
  function testMissingModules() {
    // Test that the system_dependencies_test module is marked
    // as missing a dependency.
245
    $this->drupalGet('admin/modules');
246 247 248 249 250
    $this->assertRaw(t('@module (<span class="admin-missing">missing</span>)', array('@module' => drupal_ucfirst('_missing_dependency'))), t('A module with missing dependencies is marked as such.'));
    $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[Testing][system_dependencies_test][enable]"]');
    $this->assert(count($checkbox) == 1, t('Checkbox for the module is disabled.'));

    // Force enable the system_dependencies_test module.
251
    module_enable(array('system_dependencies_test'), FALSE);
252 253 254

    // Verify that the module is forced to be disabled when submitting
    // the module page.
255
    $this->drupalPost('admin/modules', array(), t('Save configuration'));
256 257 258 259 260 261 262 263
    $this->assertText(t('The @module module is missing, so the following module will be disabled: @depends.', array('@module' => '_missing_dependency', '@depends' => 'system_dependencies_test')), t('The module missing dependencies will be disabled.'));

    // Confirm.
    $this->drupalPost(NULL, NULL, t('Continue'));

    // Verify that the module has been disabled.
    $this->assertModules(array('system_dependencies_test'), FALSE);
  }
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287

  /**
   * Tests enabling a module that depends on a module which fails hook_requirements().
   */
  function testEnableRequirementsFailureDependency() {
    $this->assertModules(array('requirements1_test'), FALSE);
    $this->assertModules(array('requirements2_test'), FALSE);

    // Attempt to install both modules at the same time.
    $edit = array();
    $edit['modules[Core][requirements1_test][enable]'] = 'requirements1_test';
    $edit['modules[Core][requirements2_test][enable]'] = 'requirements2_test';
    $this->drupalPost('admin/modules', $edit, t('Save configuration'));

    // Makes sure the modules were NOT installed.
    $this->assertText(t('Requirements 1 Test failed requirements'), t('Modules status has been updated.'));
    $this->assertModules(array('requirements1_test'), FALSE);
    $this->assertModules(array('requirements2_test'), FALSE);

    // Makes sure that already enabled modules the failing modules depend on
    // were not disabled.
    $this->assertModules(array('comment'), TRUE);

  }
288 289
}

290 291 292 293 294 295 296 297 298 299 300
/**
 * Test module dependency on specific versions.
 */
class ModuleVersionTestCase extends ModuleTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Module versions',
      'description' => 'Check module version dependencies.',
      'group' => 'Module',
    );
  }
301

302
  function setUp() {
303 304 305 306 307 308 309 310
    parent::setUp('module_test');
  }

  /**
   * Test version dependencies.
   */
  function testModuleVersions() {
    $dependencies = array(
311
      // Alternating between being compatible and incompatible with 7.x-2.4-beta3.
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
      // The first is always a compatible.
      'common_test',
      // Branch incompatibility.
      'common_test (1.x)',
      // Branch compatibility.
      'common_test (2.x)',
      // Another branch incompatibility.
      'common_test (>2.x)',
      // Another branch compatibility.
      'common_test (<=2.x)',
      // Another branch incompatibility.
      'common_test (<2.x)',
      // Another branch compatibility.
      'common_test (>=2.x)',
      // Nonsense, misses a dash. Incompatible with everything.
      'common_test (=7.x2.x, >=2.4)',
      // Core version is optional. Compatible.
329
      'common_test (=7.x-2.x, >=2.4-alpha2)',
330
      // Test !=, explicitly incompatible.
331
      'common_test (=2.x, !=2.4-beta3)',
332 333
      // Three operations. Compatible.
      'common_test (=2.x, !=2.3, <2.5)',
334 335 336 337 338 339
      // Testing extra version. Incompatible.
      'common_test (<=2.4-beta2)',
      // Testing extra version. Compatible.
      'common_test (>2.4-beta2)',
      // Testing extra version. Incompatible.
      'common_test (>2.4-rc0)',
340 341 342 343
    );
    variable_set('dependencies', $dependencies);
    $n = count($dependencies);
    for ($i = 0; $i < $n; $i++) {
344
      $this->drupalGet('admin/modules');
345
      $checkbox = $this->xpath('//input[@id="edit-modules-testing-module-test-enable"]');
346 347 348 349 350
      $this->assertEqual(!empty($checkbox[0]['disabled']), $i % 2, $dependencies[$i]);
    }
  }
}

351 352 353 354
/**
 * Test required modules functionality.
 */
class ModuleRequiredTestCase extends ModuleTestCase {
355
  public static function getInfo() {
356
    return array(
357 358 359
      'name' => 'Required modules',
      'description' => 'Attempt disabling of required modules.',
      'group' => 'Module',
360 361
    );
  }
362

363 364 365 366 367
  /**
   * Assert that core required modules cannot be disabled.
   */
  function testDisableRequired() {
    $required_modules = drupal_required_modules();
368
    $this->drupalGet('admin/modules');
369
    foreach ($required_modules as $module) {
370 371 372 373
      // Check to make sure the checkbox for required module is not found.
      $this->assertNoFieldByName('modules[Core][' . $module . '][enable]');
    }
  }
374
}
375

376
class IPAddressBlockingTestCase extends DrupalWebTestCase {
377 378
  protected $blocking_user;

379
  /**
380
   * Implement getInfo().
381
   */
382
  public static function getInfo() {
383
    return array(
384 385 386
      'name' => 'IP address blocking',
      'description' => 'Test IP address blocking.',
      'group' => 'System'
387 388 389 390
    );
  }

  /**
391
   * Implement setUp().
392 393 394 395 396
   */
  function setUp() {
    parent::setUp();

    // Create user.
397
    $this->blocking_user = $this->drupalCreateUser(array('block IP addresses'));
398
    $this->drupalLogin($this->blocking_user);
399 400 401
  }

  /**
402
   * Test a variety of user input to confirm correct validation and saving of data.
403 404
   */
  function testIPAddressValidation() {
405
    $this->drupalGet('admin/config/people/ip-blocking');
406 407 408 409

    // Block a valid IP address.
    $edit = array();
    $edit['ip'] = '192.168.1.1';
410
    $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Save'));
411
    $ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $edit['ip']))->fetchField();
412
    $this->assertTrue($ip, t('IP address found in database.'));
413 414 415 416 417
    $this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $edit['ip'])), t('IP address was blocked.'));

    // Try to block an IP address that's already blocked.
    $edit = array();
    $edit['ip'] = '192.168.1.1';
418
    $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Save'));
419 420 421 422 423
    $this->assertText(t('This IP address is already blocked.'));

    // Try to block a reserved IP address.
    $edit = array();
    $edit['ip'] = '255.255.255.255';
424
    $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Save'));
425
    $this->assertText(t('Enter a valid IP address.'));
426 427 428 429

    // Try to block a reserved IP address.
    $edit = array();
    $edit['ip'] = 'test.example.com';
430
    $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Save'));
431
    $this->assertText(t('Enter a valid IP address.'));
432 433 434 435

    // Submit an empty form.
    $edit = array();
    $edit['ip'] = '';
436
    $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Save'));
437
    $this->assertText(t('Enter a valid IP address.'));
438

439 440 441 442 443 444 445
    // Pass an IP address as a URL parameter and submit it.
    $submit_ip = '1.2.3.4';
    $this->drupalPost('admin/config/people/ip-blocking/' . $submit_ip, NULL, t('Save'));
    $ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->fetchField();
    $this->assertTrue($ip, t('IP address found in database'));
    $this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $submit_ip)), t('IP address was blocked.'));

446
    // Submit your own IP address. This fails, although it works when testing manually.
447 448 449
     // TODO: on some systems this test fails due to a bug or inconsistency in cURL.
     // $edit = array();
     // $edit['ip'] = ip_address();
450
     // $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Save'));
451
     // $this->assertText(t('You may not block your own IP address.'));
452 453
  }
}
454

455
class CronRunTestCase extends DrupalWebTestCase {
456
  /**
457
   * Implement getInfo().
458
   */
459
  public static function getInfo() {
460
    return array(
461 462 463
      'name' => 'Cron run',
      'description' => 'Test cron run.',
      'group' => 'System'
464 465 466 467 468 469 470
    );
  }

  /**
   * Test cron runs.
   */
  function testCronRun() {
471
    global $base_url;
472

473
    // Run cron anonymously without any cron key.
474
    $this->drupalGet($base_url . '/cron.php', array('external' => TRUE));
475 476 477 478
    $this->assertResponse(403);

    // Run cron anonymously with a random cron key.
    $key = $this->randomName(16);
479
    $this->drupalGet($base_url . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => $key)));
480 481 482 483
    $this->assertResponse(403);

    // Run cron anonymously with the valid cron key.
    $key = variable_get('cron_key', 'drupal');
484
    $this->drupalGet($base_url . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => $key)));
485 486
    $this->assertResponse(200);
  }
487

488
  /**
489
   * Ensure that the automatic cron run feature is working.
490 491 492 493
   *
   * In these tests we do not use REQUEST_TIME to track start time, because we
   * need the exact time when cron is triggered.
   */
494
  function testAutomaticCron() {
495 496
    // Ensure cron does not run when the cron threshold is enabled and was
    // not passed.
497 498 499 500
    $cron_last = time();
    $cron_safe_threshold = 100;
    variable_set('cron_last', $cron_last);
    variable_set('cron_safe_threshold', $cron_safe_threshold);
501
    $this->drupalGet('');
502
    $this->assertTrue($cron_last == variable_get('cron_last', NULL), t('Cron does not run when the cron threshold is not passed.'));
503 504

    // Test if cron runs when the cron threshold was passed.
505 506
    $cron_last = time() - 200;
    variable_set('cron_last', $cron_last);
507
    $this->drupalGet('');
508 509 510 511 512 513 514 515 516 517 518 519 520
    sleep(1);
    $this->assertTrue($cron_last < variable_get('cron_last', NULL), t('Cron runs when the cron threshold is passed.'));

    // Disable the cron threshold through the interface.
    $admin_user = $this->drupalCreateUser(array('administer site configuration'));
    $this->drupalLogin($admin_user);
    $this->drupalPost('admin/config/system/site-information', array('cron_safe_threshold' => 0), t('Save configuration'));
    $this->assertText(t('The configuration options have been saved.'));
    $this->drupalLogout();

    // Test if cron does not run when the cron threshold is disabled.
    $cron_last = time() - 200;
    variable_set('cron_last', $cron_last);
521
    $this->drupalGet('');
522 523 524
    $this->assertTrue($cron_last == variable_get('cron_last', NULL), t('Cron does not run when the cron threshold is disabled.'));
  }

525 526
  /**
   * Ensure that temporary files are removed.
527 528
   *
   * Create files for all the possible combinations of age and status. We are
529
   * using UPDATE statements rather than file_save() because it would set the
530
   * timestamp.
531 532 533 534
   */
  function testTempFileCleanup() {
    // Temporary file that is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
    $temp_old = file_save_data('');
535
    db_update('file_managed')
536 537 538 539 540 541
      ->fields(array(
        'status' => 0,
        'timestamp' => 1,
      ))
      ->condition('fid', $temp_old->fid)
      ->execute();
542
    $this->assertTrue(file_exists($temp_old->uri), t('Old temp file was created correctly.'));
543 544 545

    // Temporary file that is less than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
    $temp_new = file_save_data('');
546
    db_update('file_managed')
547 548 549
      ->fields(array('status' => 0))
      ->condition('fid', $temp_new->fid)
      ->execute();
550
    $this->assertTrue(file_exists($temp_new->uri), t('New temp file was created correctly.'));
551 552 553

    // Permanent file that is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
    $perm_old = file_save_data('');
554
    db_update('file_managed')
555 556 557
      ->fields(array('timestamp' => 1))
      ->condition('fid', $temp_old->fid)
      ->execute();
558
    $this->assertTrue(file_exists($perm_old->uri), t('Old permanent file was created correctly.'));
559 560 561

    // Permanent file that is newer than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
    $perm_new = file_save_data('');
562
    $this->assertTrue(file_exists($perm_new->uri), t('New permanent file was created correctly.'));
563 564

    // Run cron and then ensure that only the old, temp file was deleted.
565
    $this->cronRun();
566 567 568 569
    $this->assertFalse(file_exists($temp_old->uri), t('Old temp file was correctly removed.'));
    $this->assertTrue(file_exists($temp_new->uri), t('New temp file was correctly ignored.'));
    $this->assertTrue(file_exists($perm_old->uri), t('Old permanent file was correctly ignored.'));
    $this->assertTrue(file_exists($perm_new->uri), t('New permanent file was correctly ignored.'));
570
  }
571 572
}

573 574
class AdminMetaTagTestCase extends DrupalWebTestCase {
  /**
575
   * Implement getInfo().
576
   */
577
  public static function getInfo() {
578
    return array(
579 580 581
      'name' => 'Fingerprinting meta tag',
      'description' => 'Confirm that the fingerprinting meta tag appears as expected.',
      'group' => 'System'
582 583 584 585 586 587 588
    );
  }

  /**
   * Verify that the meta tag HTML is generated correctly.
   */
  public function testMetaTag() {
589 590
    list($version, ) = explode('.', VERSION);
    $string = '<meta name="Generator" content="Drupal ' . $version . ' (http://drupal.org)" />';
591 592 593 594
    $this->drupalGet('node');
    $this->assertRaw($string, t('Fingerprinting meta tag generated correctly.'), t('System'));
  }
}
595

596 597 598 599 600 601
/**
 * Tests custom access denied functionality.
 */
class AccessDeniedTestCase extends DrupalWebTestCase {
  protected $admin_user;

602
  public static function getInfo() {
603
    return array(
604
      'name' => '403 functionality',
605
      'description' => 'Tests page access denied functionality, including custom 403 pages.',
606
      'group' => 'System'
607 608 609 610 611 612 613
    );
  }

  function setUp() {
    parent::setUp();

    // Create an administrative user.
614
    $this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer blocks'));
615 616 617 618 619 620
    $this->drupalLogin($this->admin_user);
  }

  function testAccessDenied() {
    $this->drupalGet('admin');
    $this->assertText(t('Access denied'), t('Found the default 403 page'));
621
    $this->assertResponse(403);
622 623

    $edit = array(
624
      'title' => $this->randomName(10),
625
      'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(100)))),
626 627 628 629
    );
    $node = $this->drupalCreateNode($edit);

    // Use a custom 403 page.
630
    $this->drupalPost('admin/config/system/site-information', array('site_403' => 'node/' . $node->nid), t('Save configuration'));
631 632

    $this->drupalGet('admin');
633
    $this->assertText($node->title, t('Found the custom 403 page'));
634 635 636 637 638

    // Logout and check that the user login block is shown on custom 403 pages.
    $this->drupalLogout();

    $this->drupalGet('admin');
639
    $this->assertText($node->title, t('Found the custom 403 page'));
640 641 642 643
    $this->assertText(t('User login'), t('Blocks are shown on the custom 403 page'));

    // Log back in and remove the custom 403 page.
    $this->drupalLogin($this->admin_user);
644
    $this->drupalPost('admin/config/system/site-information', array('site_403' => ''), t('Save configuration'));
645 646 647 648 649 650

    // Logout and check that the user login block is shown on default 403 pages.
    $this->drupalLogout();

    $this->drupalGet('admin');
    $this->assertText(t('Access denied'), t('Found the default 403 page'));
651
    $this->assertResponse(403);
652
    $this->assertText(t('User login'), t('Blocks are shown on the default 403 page'));
653 654 655 656 657 658 659 660 661 662 663 664

    // Log back in, set the custom 403 page to /user and remove the block
    $this->drupalLogin($this->admin_user);
    variable_set('site_403', 'user');
    $this->drupalPost('admin/structure/block', array('user_login[region]' => '-1'), t('Save blocks'));

    // Check that we can log in from the 403 page.
    $this->drupalLogout();
    $edit = array(
      'name' => $this->admin_user->name,
      'pass' => $this->admin_user->pass_raw,
    );
665
    $this->drupalPost('admin/config/system/site-information', $edit, t('Log in'));
666 667 668

    // Check that we're still on the same page.
    $this->assertText(t('Site information'));
669 670 671
  }
}

672 673
class PageNotFoundTestCase extends DrupalWebTestCase {
  protected $admin_user;
674

675
  /**
676
   * Implement getInfo().
677
   */
678
  public static function getInfo() {
679
    return array(
680 681 682
      'name' => '404 functionality',
      'description' => "Tests page not found functionality, including custom 404 pages.",
      'group' => 'System'
683 684
    );
  }
685

686
  /**
687
   * Implement setUp().
688 689 690 691 692 693 694 695 696 697 698 699
   */
  function setUp() {
    parent::setUp();

    // Create an administrative user.
    $this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
    $this->drupalLogin($this->admin_user);
  }

  function testPageNotFound() {
    $this->drupalGet($this->randomName(10));
    $this->assertText(t('Page not found'), t('Found the default 404 page'));
700

701
    $edit = array(
702
      'title' => $this->randomName(10),
703
      'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(100)))),
704 705 706 707
    );
    $node = $this->drupalCreateNode($edit);

    // Use a custom 404 page.
708
    $this->drupalPost('admin/config/system/site-information', array('site_404' => 'node/' . $node->nid), t('Save configuration'));
709

710
    $this->drupalGet($this->randomName(10));
711
    $this->assertText($node->title, t('Found the custom 404 page'));
712 713
  }
}
714

715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
/**
 * Tests site maintenance functionality.
 */
class SiteMaintenanceTestCase extends DrupalWebTestCase {
  protected $admin_user;

  public static function getInfo() {
    return array(
      'name' => 'Site maintenance mode functionality',
      'description' => 'Test access to site while in maintenance mode.',
      'group' => 'System',
    );
  }

  function setUp() {
    parent::setUp();

    // Create a user allowed to access site in maintenance mode.
    $this->user = $this->drupalCreateUser(array('access site in maintenance mode'));
    // Create an administrative user.
    $this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'access site in maintenance mode'));
    $this->drupalLogin($this->admin_user);
  }

  /**
   * Verify site maintenance mode functionality.
   */
  function testSiteMaintenance() {
    // Turn on maintenance mode.
    $edit = array(
      'maintenance_mode' => 1,
    );
    $this->drupalPost('admin/config/development/maintenance', $edit, t('Save configuration'));

    $admin_message = t('Operating in maintenance mode. <a href="@url">Go online.</a>', array('@url' => url('admin/config/development/maintenance')));
    $user_message = t('Operating in maintenance mode.');
    $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')));

    $this->drupalGet('');
    $this->assertRaw($admin_message, t('Found the site maintenance mode message.'));

    // Logout and verify that offline message is displayed.
    $this->drupalLogout();
    $this->drupalGet('');
    $this->assertText($offline_message);
    $this->drupalGet('node');
    $this->assertText($offline_message);
    $this->drupalGet('user/register');
    $this->assertText($offline_message);
    $this->drupalGet('user/password');
    $this->assertText($offline_message);

    // Verify that user is able to log in.
    $this->drupalGet('user');
    $this->assertNoText($offline_message);
    $this->drupalGet('user/login');
    $this->assertNoText($offline_message);

    // Log in user and verify that maintenance mode message is displayed
    // directly after login.
    $edit = array(
      'name' => $this->user->name,
      'pass' => $this->user->pass_raw,
    );
    $this->drupalPost(NULL, $edit, t('Log in'));
    $this->assertText($user_message);

    // Log in administrative user and configure a custom site offline message.
    $this->drupalLogout();
    $this->drupalLogin($this->admin_user);
    $this->drupalGet('admin/config/development/maintenance');
    $this->assertNoRaw($admin_message, t('Site maintenance mode message not displayed.'));

    $offline_message = 'Sorry, not online.';
    $edit = array(
      'maintenance_mode_message' => $offline_message,
    );
    $this->drupalPost(NULL, $edit, t('Save configuration'));

    // Logout and verify that custom site offline message is displayed.
    $this->drupalLogout();
    $this->drupalGet('');
    $this->assertRaw($offline_message, t('Found the site offline message.'));
  }
}

801 802 803 804
/**
 * Tests generic date and time handling capabilities of Drupal.
 */
class DateTimeFunctionalTest extends DrupalWebTestCase {
805
  public static function getInfo() {
806
    return array(
807 808 809
      'name' => 'Date and time',
      'description' => 'Configure date and time settings. Test date formatting and time zone handling, including daylight saving time.',
      'group' => 'System',
810 811 812
    );
  }

813 814 815 816 817 818 819 820 821
  function setUp() {
    parent::setUp();

    // Create admin user and log in admin user.
    $this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
    $this->drupalLogin($this->admin_user);
  }


822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
  /**
   * Test time zones and DST handling.
   */
  function testTimeZoneHandling() {
    // Setup date/time settings for Honolulu time.
    variable_set('date_default_timezone', 'Pacific/Honolulu');
    variable_set('configurable_timezones', 0);
    variable_set('date_format_medium', 'Y-m-d H:i:s O');

    // Create some nodes with different authored-on dates.
    $date1 = '2007-01-31 21:00:00 -1000';
    $date2 = '2007-07-31 21:00:00 -1000';
    $node1 = $this->drupalCreateNode(array('created' => strtotime($date1), 'type' => 'article'));
    $node2 = $this->drupalCreateNode(array('created' => strtotime($date2), 'type' => 'article'));

    // Confirm date format and time zone.
    $this->drupalGet("node/$node1->nid");
    $this->assertText('2007-01-31 21:00:00 -1000', t('Date should be identical, with GMT offset of -10 hours.'));
    $this->drupalGet("node/$node2->nid");
    $this->assertText('2007-07-31 21:00:00 -1000', t('Date should be identical, with GMT offset of -10 hours.'));

    // Set time zone to Los Angeles time.
    variable_set('date_default_timezone', 'America/Los_Angeles');

    // Confirm date format and time zone.
    $this->drupalGet("node/$node1->nid");
    $this->assertText('2007-01-31 23:00:00 -0800', t('Date should be two hours ahead, with GMT offset of -8 hours.'));
    $this->drupalGet("node/$node2->nid");
    $this->assertText('2007-08-01 00:00:00 -0700', t('Date should be three hours ahead, with GMT offset of -7 hours.'));
  }
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922

  /**
   * Test date type configuration.
   */
  function testDateTypeConfiguration() {
    // Confirm system date types appear.
    $this->drupalGet('admin/config/regional/date-time');
    $this->assertText(t('Medium'), 'System date types appear in date type list.');
    $this->assertNoRaw('href="/admin/config/regional/date-time/types/medium/delete"', 'No delete link appear for system date types.');

    // Add custom date type.
    $this->clickLink(t('Add date type'));
    $date_type = $this->randomName(8);
    $machine_name = 'machine_' . $date_type;
    $date_format = 'd.m.Y - H:i';
    $edit = array(
      'date_type' => $date_type,
      'machine_name' => $machine_name,
      'date_format' => $date_format,
    );
    $this->drupalPost('admin/config/regional/date-time/types/add', $edit, t('Add date type'));
    $this->assertEqual($this->getUrl(), url('admin/config/regional/date-time', array('absolute' => TRUE)), t('Correct page redirection.'));
    $this->assertText(t('New date type added successfully.'), 'Date type added confirmation message appears.');
    $this->assertText($date_type, 'Custom date type appears in the date type list.');
    $this->assertText(t('delete'), 'Delete link for custom date type appears.');

    // Delete custom date type.
    $this->clickLink(t('delete'));
    $this->drupalPost('admin/config/regional/date-time/types/' . $machine_name . '/delete', array(), t('Remove'));
    $this->assertEqual($this->getUrl(), url('admin/config/regional/date-time', array('absolute' => TRUE)), t('Correct page redirection.'));
    $this->assertText(t('Removed date type ' . $date_type), 'Custom date type removed.');
  }

  /**
   * Test date format configuration.
   */
  function testDateFormatConfiguration() {
    // Confirm 'no custom date formats available' message appears.
    $this->drupalGet('admin/config/regional/date-time/formats');
    $this->assertText(t('No custom date formats available.'), 'No custom date formats message appears.');

    // Add custom date format.
    $this->clickLink(t('Add format'));
    $edit = array(
      'date_format' => 'Y',
    );
    $this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
    $this->assertEqual($this->getUrl(), url('admin/config/regional/date-time/formats', array('absolute' => TRUE)), t('Correct page redirection.'));
    $this->assertNoText(t('No custom date formats available.'), 'No custom date formats message does not appear.');
    $this->assertText(t('Custom date format added.'), 'Custom date format added.');

    // Ensure custom date format appears in date type configuration options.
    $this->drupalGet('admin/config/regional/date-time');
    $this->assertRaw('<option value="Y">', 'Custom date format appears in options.');

    // Edit custom date format.
    $this->drupalGet('admin/config/regional/date-time/formats');
    $this->clickLink(t('edit'));
    $edit = array(
      'date_format' => 'Y m',
    );
    $this->drupalPost($this->getUrl(), $edit, t('Save format'));
    $this->assertEqual($this->getUrl(), url('admin/config/regional/date-time/formats', array('absolute' => TRUE)), t('Correct page redirection.'));
    $this->assertText(t('Custom date format updated.'), 'Custom date format successfully updated.');

    // Delete custom date format.
    $this->clickLink(t('delete'));
    $this->drupalPost($this->getUrl(), array(), t('Remove'));
    $this->assertEqual($this->getUrl(), url('admin/config/regional/date-time/formats', array('absolute' => TRUE)), t('Correct page redirection.'));
    $this->assertText(t('Removed date format'), 'Custom date format removed successfully.');
  }
923 924
}

925 926 927 928 929
class PageTitleFiltering extends DrupalWebTestCase {
  protected $content_user;
  protected $saved_title;

  /**
930
   * Implement getInfo().
931
   */
932
  public static function getInfo() {
933
    return array(
934
      'name' => 'HTML in page titles',
935
      'description' => 'Tests correct handling or conversion by drupal_set_title() and drupal_get_title() and checks the correct escaping of site name and slogan.',
936
      'group' => 'System'
937 938 939 940
    );
  }

  /**
941
   * Implement setUp().
942 943 944 945
   */
  function setUp() {
    parent::setUp();

946
    $this->content_user = $this->drupalCreateUser(array('create page content', 'access content', 'administer themes', 'administer site configuration'));
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974
    $this->drupalLogin($this->content_user);
    $this->saved_title = drupal_get_title();
  }

  /**
   * Reset page title.
   */
  function tearDown() {
    // Restore the page title.
    drupal_set_title($this->saved_title, PASS_THROUGH);

    parent::tearDown();
  }

  /**
   * Tests the handling of HTML by drupal_set_title() and drupal_get_title()
   */
  function testTitleTags() {
    $title = "string with <em>HTML</em>";
    // drupal_set_title's $filter is CHECK_PLAIN by default, so the title should be
    // returned with check_plain().
    drupal_set_title($title, CHECK_PLAIN);
    $this->assertTrue(strpos(drupal_get_title(), '<em>') === FALSE, t('Tags in title converted to entities when $output is CHECK_PLAIN.'));
    // drupal_set_title's $filter is passed as PASS_THROUGH, so the title should be
    // returned with HTML.
    drupal_set_title($title, PASS_THROUGH);
    $this->assertTrue(strpos(drupal_get_title(), '<em>') !== FALSE, t('Tags in title are not converted to entities when $output is PASS_THROUGH.'));
    // Generate node content.
975
    $langcode = LANGUAGE_NONE;
976
    $edit = array(
977 978
      "title" => '!SimpleTest! ' . $title . $this->randomName(20),
      "body[$langcode][0][value]" => '!SimpleTest! test body' . $this->randomName(200),
979 980 981 982
    );
    // Create the node with HTML in the title.
    $this->drupalPost('node/add/page', $edit, t('Save'));

983
    $node = $this->drupalGetNodeByTitle($edit["title"]);
984 985
    $this->assertNotNull($node, 'Node created and found in database');
    $this->drupalGet("node/" . $node->nid);
986
    $this->assertText(check_plain($edit["title"]), 'Check to make sure tags in the node title are converted.');
987
  }
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
  /**
   * Test if the title of the site is XSS proof.
   */
  function testTitleXSS() {
    // Set some title with JavaScript and HTML chars to escape.
    $title = '</title><script type="text/javascript">alert("Title XSS!");</script> & < > " \' ';
    $title_filtered = check_plain($title);

    $slogan = '<script type="text/javascript">alert("Slogan XSS!");</script>';
    $slogan_filtered = filter_xss_admin($slogan);

    // Activate needed appearance settings.
    $edit = array(
      'toggle_name'           => TRUE,
      'toggle_slogan'         => TRUE,
      'toggle_main_menu'      => TRUE,
      'toggle_secondary_menu' => TRUE,
    );
    $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration'));

    // Set title and slogan.
    $edit = array(
      'site_name'    => $title,
      'site_slogan'  => $slogan,
    );
    $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration'));

    // Load frontpage.
    $this->drupalGet('');

    // Test the title.
    $this->assertNoRaw($title, 'Check for the unfiltered version of the title.');
    // Adding </title> so we do not test the escaped version from drupal_set_title().
    $this->assertRaw($title_filtered . '</title>', 'Check for the filtered version of the title.');

    // Test the slogan.
    // Currently Garland is not displaying the slogan so this test is escaped.
    $this->assertNoRaw($slogan, 'Check for the unfiltered version of the slogan.');
    $this->assertRaw($slogan_filtered, 'Check for the filtered version of the slogan.');
  }
1028
}
1029 1030 1031 1032 1033 1034

/**
 * Test front page functionality and administration.
 */
class FrontPageTestCase extends DrupalWebTestCase {

1035
  public static function getInfo() {
1036
    return array(
1037 1038 1039
      'name' => 'Front page',
      'description' => 'Tests front page functionality and administration.',
      'group' => 'System',
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
    );
  }

  function setUp() {
    parent::setUp('system_test');

    // Create admin user, log in admin user, and create one node.
    $this->admin_user = $this->drupalCreateUser(array('access content', 'administer site configuration'));
    $this->drupalLogin($this->admin_user);
    $this->node_path = "node/" . $this->drupalCreateNode(array('promote' => 1))->nid;

    // Enable front page logging in system_test.module.
    variable_set('front_page_output', 1);
  }

  /**
   * Test front page functionality.
   */
  function testDrupalIsFrontPage() {
    $this->drupalGet('');
    $this->assertText(t('On front page.'), t('Path is the front page.'));
    $this->drupalGet('node');
    $this->assertText(t('On front page.'), t('Path is the front page.'));
    $this->drupalGet($this->node_path);
    $this->assertNoText(t('On front page.'), t('Path is not the front page.'));

    // Change the front page to an invalid path.
    $edit = array('site_frontpage' => 'kittens');
1068
    $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration'));
1069 1070 1071 1072
    $this->assertText(t("The path '@path' is either invalid or you do not have access to it.", array('@path' => $edit['site_frontpage'])));

    // Change the front page to a valid path.
    $edit['site_frontpage'] = $this->node_path;
1073
    $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration'));
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
    $this->assertText(t('The configuration options have been saved.'), t('The front page path has been saved.'));

    $this->drupalGet('');
    $this->assertText(t('On front page.'), t('Path is the front page.'));
    $this->drupalGet('node');
    $this->assertNoText(t('On front page.'), t('Path is not the front page.'));
    $this->drupalGet($this->node_path);
    $this->assertText(t('On front page.'), t('Path is the front page.'));
  }
}
1084 1085

class SystemBlockTestCase extends DrupalWebTestCase {
1086
  public static function getInfo() {
1087
    return array(
1088 1089 1090
      'name' => 'Block functionality',
      'description' => 'Configure and move powered-by block.',
      'group' => 'System',
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
    );
  }

  function setUp() {
    parent::setUp();

    // Create and login user
    $admin_user = $this->drupalCreateUser(array('administer blocks'));
    $this->drupalLogin($admin_user);
  }

  /**
   * Test displaying and hiding the powered-by block.
   */
  function testPoweredByBlock() {
1106
    // Set block title and some settings to confirm that the interface is available.
1107
    $this->drupalPost('admin/structure/block/manage/system/powered-by/configure', array('title' => $this->randomName(8)), t('Save block'));
1108 1109 1110 1111 1112
    $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));

    // Set the powered-by block to the footer region.
    $edit = array();
    $edit['system_powered-by[region]'] = 'footer';
1113
    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
1114
    $this->assertText(t('The block settings have been updated.'), t('Block successfully moved to footer region.'));
1115 1116

    // Confirm that the block is being displayed.
1117
    $this->drupalGet('node');
1118 1119 1120 1121 1122
    $this->assertRaw('id="block-system-powered-by"', t('Block successfully being displayed on the page.'));

    // Set the block to the disabled region.
    $edit = array();
    $edit['system_powered-by[region]'] = '-1';
1123
    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
1124 1125 1126 1127 1128 1129 1130

    // Confirm that the block is hidden.
    $this->assertNoRaw('id="block-system-powered-by"', t('Block no longer appears on page.'));

    // For convenience of developers, set the block to it's default settings.
    $edit = array();
    $edit['system_powered-by[region]'] = 'footer';
1131
    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
1132
    $this->drupalPost('admin/structure/block/manage/system/powered-by/configure', array('title' => ''), t('Save block'));
1133
  }
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
}

/**
 * Test main content rendering fallback provided by system module.
 */
class SystemMainContentFallback extends DrupalWebTestCase {
  protected $admin_user;
  protected $web_user;

  public static function getInfo() {
    return array(
      'name' => 'Main content rendering fallback',
      'description' => ' Test system module main content rendering fallback.',
      'group' => 'System',
    );
  }

  function setUp() {
    parent::setUp('system_test');

    // Create and login admin user.
    $this->admin_user = $this->drupalCreateUser(array(
      'access administration pages',
      'administer site configuration',
1158
      'administer modules',
1159 1160 1161 1162
      'administer blocks',
      'administer nodes',
    ));
    $this->drupalLogin($this->admin_user);
1163

1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174
    // Create a web user.
    $this->web_user = $this->drupalCreateUser(array('access user profiles', 'access content'));
  }

  /**
   * Test availability of main content.
   */
  function testMainContentFallback() {
    $edit = array();
    // Disable the dashboard module, which depends on the block module.
    $edit['modules[Core][dashboard][enable]'] = FALSE;
1175
    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
1176 1177 1178
    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
    // Disable the block module.
    $edit['modules[Core][block][enable]'] = FALSE;
1179
    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
1180 1181 1182 1183 1184 1185
    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
    module_list(TRUE);
    $this->assertFalse(module_exists('block'), t('Block module disabled.'));

    // At this point, no region is filled and fallback should be triggered.
    $this->drupalGet('admin/config/system/site-information');
1186
    $this->assertField('site_name', t('Admin interface still available.'));
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206

    // Fallback should not trigger when another module is handling content.
    $this->drupalGet('system-test/main-content-handling');
    $this->assertRaw('id="system-test-content"', t('Content handled by another module'));
    $this->assertText(t('Content to test main content fallback'), t('Main content still displayed.'));

    // Fallback should trigger when another module
    // indicates that it is not handling the content.
    $this->drupalGet('system-test/main-content-fallback');
    $this->assertText(t('Content to test main content fallback'), t('Main content fallback properly triggers.'));

    // Fallback should not trigger when another module is handling content.
    // Note that this test ensures that no duplicate
    // content gets created by the fallback.
    $this->drupalGet('system-test/main-content-duplication');
    $this->assertNoText(t('Content to test main content fallback'), t('Main content not duplicated.'));

    // Request a user* page and see if it is displayed.
    $this->drupalLogin($this->web_user);
    $this->drupalGet('user/' . $this->web_user->uid . '/edit');
1207
    $this->assertField('mail', t('User interface still available.'));
1208 1209 1210 1211 1212

    // Enable the block module again.
    $this->drupalLogin($this->admin_user);
    $edit = array();
    $edit['modules[Core][block][enable]'] = 'block';
1213
    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
1214 1215 1216 1217
    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
    module_list(TRUE);
    $this->assertTrue(module_exists('block'), t('Block module re-enabled.'));
  }
1218 1219
}

1220 1221
class SystemSettingsForm extends DrupalWebTestCase {
  /**
1222
   * Implement getInfo().
1223
   */
1224
  public static function getInfo() {
1225
    return array(
1226 1227 1228
      'name' => 'System setting forms',
      'description' => 'Tests correctness of system_settings_form() processing.',
      'group' => 'System'
1229 1230 1231 1232
    );
  }

  /**
1233
   * Implement setUp().
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
   */
  function setUp() {
    parent::setUp();

    variable_set('system_settings_form_test', TRUE);
    variable_set('system_settings_form_test_4', TRUE);
  }

  /**
   * Reset page title.
   */
  function tearDown() {
    variable_del('system_settings_form_test');
    variable_del('system_settings_form_test_4');
1248

1249 1250
    parent::tearDown();
  }
1251

1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295
  /**
   * Tests the handling of automatic defaults in systems_settings_form().
   */
  function testAutomaticDefaults() {
    $form['system_settings_form_test'] = array(
      '#type' => 'checkbox',
      '#default_value' => FALSE,
    );

    $form['system_settings_form_test_2'] = array(
      '#type' => 'checkbox',
      '#default_value' => FALSE,
    );

    $form['system_settings_form_test_3'] = array(
      '#type' => 'checkbox',
      '#default_value' => TRUE,
    );

    $form['has_children']['system_settings_form_test_4'] = array(
      '#type' => 'checkbox',
      '#default_value' => FALSE,
    );

    $form['has_children']['system_settings_form_test_5'] = array(
      '#type' => 'checkbox',
      '#default_value' => TRUE,
    );

    $automatic = system_settings_form($form, FALSE);
    $this->assertFalse($automatic['system_settings_form_test']['#default_value']);
    $this->assertFalse($automatic['system_settings_form_test_2']['#default_value']);
    $this->assertTrue($automatic['system_settings_form_test_3']['#default_value']);
    $this->assertFalse($automatic['has_children']['system_settings_form_test_4']['#default_value']);
    $this->assertTrue($automatic['has_children']['system_settings_form_test_5']['#default_value']);

    $no_automatic = system_settings_form($form);
    $this->assertTrue($no_automatic['system_settings_form_test']['#default_value']);
    $this->assertFalse($no_automatic['system_settings_form_test_2']['#default_value']);
    $this->assertTrue($no_automatic['system_settings_form_test_3']['#default_value']);
    $this->assertTrue($no_automatic['has_children']['system_settings_form_test_4']['#default_value']);
    $this->assertTrue($no_automatic['has_children']['system_settings_form_test_5']['#default_value']);
  }
}
1296 1297 1298 1299 1300

/**
 * Tests for the theme interface functionality.
 */
class SystemThemeFunctionalTest extends DrupalWebTestCase {
1301
  public static function getInfo() {
1302
    return array(
1303 1304 1305
      'name' => 'Theme interface functionality',
      'description' => 'Tests the theme interface functionality by enabling and switching themes, and using an administration theme.',
      'group' => 'System',
1306 1307 1308 1309 1310 1311
    );
  }

  function setUp() {
    parent::setUp();

1312
    $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer themes', 'bypass node access'));
1313 1314 1315 1316
    $this->drupalLogin($this->admin_user);
    $this->node = $this->drupalCreateNode();
  }

1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
  /**
   * Test the theme settings form.
   */
  function testThemeSettings() {
    // Specify a filesystem path to be used for the logo.
    $file = current($this->drupalGetTestFiles('image'));
    $edit = array(
      'default_logo' => FALSE,
      'logo_path' => $file->uri,
    );
    $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration'));
    $this->drupalGet('node');
    $this->assertRaw($file->uri, t('Logo path successfully changed.'));
1330

1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
    // Upload a file to use for the logo.
    $file = current($this->drupalGetTestFiles('image'));
    $edit = array(
      'default_logo' => FALSE,
      'logo_path' => '',
      'files[logo_upload]' => drupal_realpath($file->uri),
    );
    $options = array();
    $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration'), $options);
    $this->drupalGet('node');
    $this->assertRaw($file->name, t('Logo file successfully uploaded.'));
  }

1344 1345 1346 1347
  /**
   * Test the administration theme functionality.
   */
  function testAdministrationTheme() {
1348 1349
    theme_enable(array('stark'));
    variable_set('theme_default', 'stark');
1350 1351 1352 1353 1354
    // Enable an administration theme and show it on the node admin pages.
    $edit = array(
      'admin_theme' => 'garland',
      'node_admin_theme' => TRUE,
    );
1355
    $this->drupalPost('admin/appearance', $edit, t('Save configuration'));
1356

1357
    $this->drupalGet('admin/config');
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372
    $this->assertRaw('themes/garland', t('Administration theme used on an administration page.'));

    $this->drupalGet('node/' . $this->node->nid);
    $this->assertRaw('themes/stark', t('Site default theme used on node page.'));

    $this->drupalGet('node/add');
    $this->assertRaw('themes/garland', t('Administration theme used on the add content page.'));

    $this->drupalGet('node/' . $this->node->nid . '/edit');
    $this->assertRaw('themes/garland', t('Administration theme used on the edit content page.'));

    // Disable the admin theme on the node admin pages.
    $edit = array(
      'node_admin_theme' => FALSE,
    );
1373
    $this->drupalPost('admin/appearance', $edit, t('Save configuration'));
1374

1375
    $this->drupalGet('admin/config');
1376 1377 1378 1379 1380 1381
    $this->assertRaw('themes/garland', t('Administration theme used on an administration page.'));

    $this->drupalGet('node/add');
    $this->assertRaw('themes/stark', t('Site default theme used on the add content page.'));

    // Reset to the default theme settings.
Dries's avatar