block.test 38.3 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 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 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 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 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 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 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 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 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 975 976 977 978 979
<?php

/**
 * @file
 * Tests for block.module.
 */

class BlockTestCase extends DrupalWebTestCase {
  protected $regions;
  protected $admin_user;

  public static function getInfo() {
    return array(
      'name' => 'Block functionality',
      'description' => 'Add, edit and delete custom block. Configure and move a module-defined block.',
      'group' => 'Block',
    );
  }

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

    // Create and log in an administrative user having access to the Full HTML
    // text format.
    $full_html_format = filter_format_load('full_html');
    $this->admin_user = $this->drupalCreateUser(array(
      'administer blocks',
      filter_permission_name($full_html_format),
      'access administration pages',
    ));
    $this->drupalLogin($this->admin_user);

    // Define the existing regions
    $this->regions = array();
    $this->regions[] = 'header';
    $this->regions[] = 'sidebar_first';
    $this->regions[] = 'content';
    $this->regions[] = 'sidebar_second';
    $this->regions[] = 'footer';
  }

  /**
   * Test creating custom block, moving it to a specific region and then deleting it.
   */
  function testCustomBlock() {
    // Confirm that the add block link appears on block overview pages.
    $this->drupalGet('admin/structure/block');
    $this->assertRaw(l('Add block', 'admin/structure/block/add'), 'Add block link is present on block overview page for default theme.');
    $this->drupalGet('admin/structure/block/list/seven');
    $this->assertRaw(l('Add block', 'admin/structure/block/list/seven/add'), 'Add block link is present on block overview page for non-default theme.');

    // Confirm that hidden regions are not shown as options for block placement
    // when adding a new block.
    theme_enable(array('stark'));
    $themes = list_themes();
    $this->drupalGet('admin/structure/block/add');
    foreach ($themes as $key => $theme) {
      if ($theme->status) {
        foreach ($theme->info['regions_hidden'] as $hidden_region) {
          $elements = $this->xpath('//select[@id=:id]//option[@value=:value]', array(':id' => 'edit-regions-' . $key, ':value' => $hidden_region));
          $this->assertFalse(isset($elements[0]), format_string('The hidden region @region is not available for @theme.', array('@region' => $hidden_region, '@theme' => $key)));
        }
      }
    }

    // Add a new custom block by filling out the input form on the admin/structure/block/add page.
    $custom_block = array();
    $custom_block['info'] = $this->randomName(8);
    $custom_block['title'] = $this->randomName(8);
    $custom_block['body[value]'] = $this->randomName(32);
    $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));

    // Confirm that the custom block has been created, and then query the created bid.
    $this->assertText(t('The block has been created.'), 'Custom block successfully created.');
    $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();

    // Check to see if the custom block was created by checking that it's in the database.
    $this->assertNotNull($bid, 'Custom block found in database');

    // Check that block_block_view() returns the correct title and content.
    $data = block_block_view($bid);
    $format = db_query("SELECT format FROM {block_custom} WHERE bid = :bid", array(':bid' => $bid))->fetchField();
    $this->assertTrue(array_key_exists('subject', $data) && empty($data['subject']), 'block_block_view() provides an empty block subject, since custom blocks do not have default titles.');
    $this->assertEqual(check_markup($custom_block['body[value]'], $format), $data['content'], 'block_block_view() provides correct block content.');

    // Check whether the block can be moved to all available regions.
    $custom_block['module'] = 'block';
    $custom_block['delta'] = $bid;
    foreach ($this->regions as $region) {
      $this->moveBlockToRegion($custom_block, $region);
    }

    // Verify presence of configure and delete links for custom block.
    $this->drupalGet('admin/structure/block');
    $this->assertLinkByHref('admin/structure/block/manage/block/' . $bid . '/configure', 0, 'Custom block configure link found.');
    $this->assertLinkByHref('admin/structure/block/manage/block/' . $bid . '/delete', 0, 'Custom block delete link found.');

    // Set visibility only for authenticated users, to verify delete functionality.
    $edit = array();
    $edit['roles[' . DRUPAL_AUTHENTICATED_RID . ']'] = TRUE;
    $this->drupalPost('admin/structure/block/manage/block/' . $bid . '/configure', $edit, t('Save block'));

    // Delete the created custom block & verify that it's been deleted and no longer appearing on the page.
    $this->clickLink(t('delete'));
    $this->drupalPost('admin/structure/block/manage/block/' . $bid . '/delete', array(), t('Delete'));
    $this->assertRaw(t('The block %title has been removed.', array('%title' => $custom_block['info'])), 'Custom block successfully deleted.');
    $this->assertNoText(t($custom_block['title']), 'Custom block no longer appears on page.');
    $count = db_query("SELECT 1 FROM {block_role} WHERE module = :module AND delta = :delta", array(':module' => $custom_block['module'], ':delta' => $custom_block['delta']))->fetchField();
    $this->assertFalse($count, 'Table block_role being cleaned.');
  }

  /**
   * Test creating custom block using Full HTML.
   */
  function testCustomBlockFormat() {
    // Add a new custom block by filling out the input form on the admin/structure/block/add page.
    $custom_block = array();
    $custom_block['info'] = $this->randomName(8);
    $custom_block['title'] = $this->randomName(8);
    $custom_block['body[value]'] = '<h1>Full HTML</h1>';
    $full_html_format = filter_format_load('full_html');
    $custom_block['body[format]'] = $full_html_format->format;
    $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));

    // Set the created custom block to a specific region.
    $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
    $edit = array();
    $edit['blocks[block_' . $bid . '][region]'] = $this->regions[1];
    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));

    // Confirm that the custom block is being displayed using configured text format.
    $this->drupalGet('node');
    $this->assertRaw('<h1>Full HTML</h1>', 'Custom block successfully being displayed using Full HTML.');

    // Confirm that a user without access to Full HTML can not see the body field,
    // but can still submit the form without errors.
    $block_admin = $this->drupalCreateUser(array('administer blocks'));
    $this->drupalLogin($block_admin);
    $this->drupalGet('admin/structure/block/manage/block/' . $bid . '/configure');
    $this->assertFieldByXPath("//textarea[@name='body[value]' and @disabled='disabled']", t('This field has been disabled because you do not have sufficient permissions to edit it.'), 'Body field contains denied message');
    $this->drupalPost('admin/structure/block/manage/block/' . $bid . '/configure', array(), t('Save block'));
    $this->assertNoText(t('Ensure that each block description is unique.'));

    // Confirm that the custom block is still being displayed using configured text format.
    $this->drupalGet('node');
    $this->assertRaw('<h1>Full HTML</h1>', 'Custom block successfully being displayed using Full HTML.');
  }

  /**
   * Test block visibility.
   */
  function testBlockVisibility() {
    $block = array();

    // Create a random title for the block
    $title = $this->randomName(8);

    // Create the custom block
    $custom_block = array();
    $custom_block['info'] = $this->randomName(8);
    $custom_block['title'] = $title;
    $custom_block['body[value]'] = $this->randomName(32);
    $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));

    $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
    $block['module'] = 'block';
    $block['delta'] = $bid;
    $block['title'] = $title;

    // Set the block to be hidden on any user path, and to be shown only to
    // authenticated users.
    $edit = array();
    $edit['pages'] = 'user*';
    $edit['roles[' . DRUPAL_AUTHENTICATED_RID . ']'] = TRUE;
    $this->drupalPost('admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure', $edit, t('Save block'));

    // Move block to the first sidebar.
    $this->moveBlockToRegion($block, $this->regions[1]);

    $this->drupalGet('');
    $this->assertText($title, 'Block was displayed on the front page.');

    $this->drupalGet('user');
    $this->assertNoText($title, 'Block was not displayed according to block visibility rules.');

    $this->drupalGet('USER/' . $this->admin_user->uid);
    $this->assertNoText($title, 'Block was not displayed according to block visibility rules regardless of path case.');

    // Confirm that the block is not displayed to anonymous users.
    $this->drupalLogout();
    $this->drupalGet('');
    $this->assertNoText($title, 'Block was not displayed to anonymous users.');
  }

  /**
   * Test block visibility when using "pages" restriction but leaving
   * "pages" textarea empty
   */
  function testBlockVisibilityListedEmpty() {
    $block = array();

    // Create a random title for the block
    $title = $this->randomName(8);

    // Create the custom block
    $custom_block = array();
    $custom_block['info'] = $this->randomName(8);
    $custom_block['title'] = $title;
    $custom_block['body[value]'] = $this->randomName(32);
    $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));

    $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
    $block['module'] = 'block';
    $block['delta'] = $bid;
    $block['title'] = $title;

    // Move block to the first sidebar.
    $this->moveBlockToRegion($block, $this->regions[1]);

    // Set the block to be hidden on any user path, and to be shown only to
    // authenticated users.
    $edit = array();
    $edit['visibility'] = BLOCK_VISIBILITY_LISTED;
    $this->drupalPost('admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure', $edit, t('Save block'));

    $this->drupalGet('');
    $this->assertNoText($title, 'Block was not displayed according to block visibility rules.');

    $this->drupalGet('user');
    $this->assertNoText($title, 'Block was not displayed according to block visibility rules regardless of path case.');

    // Confirm that the block is not displayed to anonymous users.
    $this->drupalLogout();
    $this->drupalGet('');
    $this->assertNoText($title, 'Block was not displayed to anonymous users.');
  }

  /**
   * Test user customization of block visibility.
   */
  function testBlockVisibilityPerUser() {
    $block = array();

    // Create a random title for the block.
    $title = $this->randomName(8);

    // Create our custom test block.
    $custom_block = array();
    $custom_block['info'] = $this->randomName(8);
    $custom_block['title'] = $title;
    $custom_block['body[value]'] = $this->randomName(32);
    $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));

    $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
    $block['module'] = 'block';
    $block['delta'] = $bid;
    $block['title'] = $title;

    // Move block to the first sidebar.
    $this->moveBlockToRegion($block, $this->regions[1]);

    // Set the block to be customizable per user, visible by default.
    $edit = array();
    $edit['custom'] = BLOCK_CUSTOM_ENABLED;
    $this->drupalPost('admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure', $edit, t('Save block'));

    // Disable block visibility for the admin user.
    $edit = array();
    $edit['block[' . $block['module'] . '][' . $block['delta'] . ']'] = FALSE;
    $this->drupalPost('user/' . $this->admin_user->uid . '/edit', $edit, t('Save'));

    $this->drupalGet('');
    $this->assertNoText($block['title'], 'Block was not displayed according to per user block visibility setting.');

    // Set the block to be customizable per user, hidden by default.
    $edit = array();
    $edit['custom'] = BLOCK_CUSTOM_DISABLED;
    $this->drupalPost('admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure', $edit, t('Save block'));

    // Enable block visibility for the admin user.
    $edit = array();
    $edit['block[' . $block['module'] . '][' . $block['delta'] . ']'] = TRUE;
    $this->drupalPost('user/' . $this->admin_user->uid . '/edit', $edit, t('Save'));

    $this->drupalGet('');
    $this->assertText($block['title'], 'Block was displayed according to per user block visibility setting.');
  }

  /**
   * Test configuring and moving a module-define block to specific regions.
   */
  function testBlock() {
    // Select the Navigation block to be configured and moved.
    $block = array();
    $block['module'] = 'system';
    $block['delta'] = 'management';
    $block['title'] = $this->randomName(8);

    // Set block title to confirm that interface works and override any custom titles.
    $this->drupalPost('admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure', array('title' => $block['title']), t('Save block'));
    $this->assertText(t('The block configuration has been saved.'), 'Block title set.');
    $bid = db_query("SELECT bid FROM {block} WHERE module = :module AND delta = :delta", array(
      ':module' => $block['module'],
      ':delta' => $block['delta'],
    ))->fetchField();

    // Check to see if the block was created by checking that it's in the database.
    $this->assertNotNull($bid, 'Block found in database');

    // Check whether the block can be moved to all available regions.
    foreach ($this->regions as $region) {
      $this->moveBlockToRegion($block, $region);
    }

    // Set the block to the disabled region.
    $edit = array();
    $edit['blocks[' . $block['module'] . '_' . $block['delta'] . '][region]'] = '-1';
    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));

    // Confirm that the block was moved to the proper region.
    $this->assertText(t('The block settings have been updated.'), 'Block successfully move to disabled region.');
    $this->assertNoText(t($block['title']), 'Block no longer appears on page.');

    // Confirm that the region's xpath is not available.
    $xpath = $this->buildXPathQuery('//div[@id=:id]/*', array(':id' => 'block-block-' . $bid));
    $this->assertNoFieldByXPath($xpath, FALSE, 'Custom block found in no regions.');

    // For convenience of developers, put the navigation block back.
    $edit = array();
    $edit['blocks[' . $block['module'] . '_' . $block['delta'] . '][region]'] = $this->regions[1];
    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
    $this->assertText(t('The block settings have been updated.'), 'Block successfully move to first sidebar region.');

    $this->drupalPost('admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure', array('title' => 'Navigation'), t('Save block'));
    $this->assertText(t('The block configuration has been saved.'), 'Block title set.');
  }

  function moveBlockToRegion($block, $region) {
    // Set the created block to a specific region.
    $edit = array();
    $edit['blocks[' . $block['module'] . '_' . $block['delta'] . '][region]'] = $region;
    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));

    // Confirm that the block was moved to the proper region.
    $this->assertText(t('The block settings have been updated.'), format_string('Block successfully moved to %region_name region.', array( '%region_name' => $region)));

    // Confirm that the block is being displayed.
    $this->drupalGet('node');
    $this->assertText(t($block['title']), 'Block successfully being displayed on the page.');

    // Confirm that the custom block was found at the proper region.
    $xpath = $this->buildXPathQuery('//div[@class=:region-class]//div[@id=:block-id]/*', array(
      ':region-class' => 'region region-' . str_replace('_', '-', $region),
      ':block-id' => 'block-' . $block['module'] . '-' . $block['delta'],
    ));
    $this->assertFieldByXPath($xpath, NULL, format_string('Custom block found in %region_name region.', array('%region_name' => $region)));
  }

  /**
   * Test _block_rehash().
   */
  function testBlockRehash() {
    module_enable(array('block_test'));
    $this->assertTrue(module_exists('block_test'), 'Test block module enabled.');

    // Our new block should be inserted in the database when we visit the
    // block management page.
    $this->drupalGet('admin/structure/block');
    // Our test block's caching should default to DRUPAL_CACHE_PER_ROLE.
    $current_caching = db_query("SELECT cache FROM {block} WHERE module = 'block_test' AND delta = 'test_cache'")->fetchField();
    $this->assertEqual($current_caching, DRUPAL_CACHE_PER_ROLE, 'Test block cache mode defaults to DRUPAL_CACHE_PER_ROLE.');

    // Disable caching for this block.
    variable_set('block_test_caching', DRUPAL_NO_CACHE);
    // Flushing all caches should call _block_rehash().
    drupal_flush_all_caches();
    // Verify that the database is updated with the new caching mode.
    $current_caching = db_query("SELECT cache FROM {block} WHERE module = 'block_test' AND delta = 'test_cache'")->fetchField();
    $this->assertEqual($current_caching, DRUPAL_NO_CACHE, "Test block's database entry updated to DRUPAL_NO_CACHE.");
  }
}

class NonDefaultBlockAdmin extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Non default theme admin',
      'description' => 'Check the administer page for non default theme.',
      'group' => 'Block',
    );
  }

  /**
   * Test non-default theme admin.
   */
  function testNonDefaultBlockAdmin() {
    $admin_user = $this->drupalCreateUser(array('administer blocks', 'administer themes'));
    $this->drupalLogin($admin_user);
    theme_enable(array('stark'));
    $this->drupalGet('admin/structure/block/list/stark');
  }
}

/**
 * Test blocks correctly initialized when picking a new default theme.
 */
class NewDefaultThemeBlocks extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'New default theme blocks',
      'description' => 'Checks that the new default theme gets blocks.',
      'group' => 'Block',
    );
  }

  /**
   * Check the enabled Bartik blocks are correctly copied over.
   */
  function testNewDefaultThemeBlocks() {
    // Create administrative user.
    $admin_user = $this->drupalCreateUser(array('administer themes'));
    $this->drupalLogin($admin_user);

    // Ensure no other theme's blocks are in the block table yet.
    $themes = array();
    $themes['default'] = variable_get('theme_default', 'bartik');
    if ($admin_theme = variable_get('admin_theme')) {
      $themes['admin'] = $admin_theme;
    }
    $count = db_query_range('SELECT 1 FROM {block} WHERE theme NOT IN (:themes)', 0, 1, array(':themes' => $themes))->fetchField();
    $this->assertFalse($count, 'Only the default theme and the admin theme have blocks.');

    // Populate list of all blocks for matching against new theme.
    $blocks = array();
    $result = db_query('SELECT * FROM {block} WHERE theme = :theme', array(':theme' => $themes['default']));
    foreach ($result as $block) {
      // $block->theme and $block->bid will not match, so remove them.
      unset($block->theme, $block->bid);
      $blocks[$block->module][$block->delta] = $block;
    }

    // Turn on the Stark theme and ensure that it contains all of the blocks
    // the default theme had.
    theme_enable(array('stark'));
    variable_set('theme_default', 'stark');
    $result = db_query('SELECT * FROM {block} WHERE theme = :theme', array(':theme' => 'stark'));
    foreach ($result as $block) {
      unset($block->theme, $block->bid);
      $this->assertEqual($blocks[$block->module][$block->delta], $block, format_string('Block %name matched', array('%name' => $block->module . '-' . $block->delta)));
    }
  }
}

/**
 * Test the block system with admin themes.
 */
class BlockAdminThemeTestCase extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Admin theme block admin accessibility',
      'description' => "Check whether the block administer page for a disabled theme accessible if and only if it's the admin theme.",
      'group' => 'Block',
    );
  }

  /**
   * Check for the accessibility of the admin theme on the  block admin page.
   */
  function testAdminTheme() {
    // Create administrative user.
    $admin_user = $this->drupalCreateUser(array('administer blocks', 'administer themes'));
    $this->drupalLogin($admin_user);

    // Ensure that access to block admin page is denied when theme is disabled.
    $this->drupalGet('admin/structure/block/list/stark');
    $this->assertResponse(403, 'The block admin page for a disabled theme can not be accessed');

    // Enable admin theme and confirm that tab is accessible.
    $edit['admin_theme'] = 'stark';
    $this->drupalPost('admin/appearance', $edit, t('Save configuration'));
    $this->drupalGet('admin/structure/block/list/stark');
    $this->assertResponse(200, 'The block admin page for the admin theme can be accessed');
  }
}

/**
 * Test block caching.
 */
class BlockCacheTestCase extends DrupalWebTestCase {
  protected $admin_user;
  protected $normal_user;
  protected $normal_user_alt;

  public static function getInfo() {
    return array(
      'name' => 'Block caching',
      'description' => 'Test block caching.',
      'group' => 'Block',
    );
  }

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

    // Create an admin user, log in and enable test blocks.
    $this->admin_user = $this->drupalCreateUser(array('administer blocks', 'access administration pages'));
    $this->drupalLogin($this->admin_user);

    // Create additional users to test caching modes.
    $this->normal_user = $this->drupalCreateUser();
    $this->normal_user_alt = $this->drupalCreateUser();
    // Sync the roles, since drupalCreateUser() creates separate roles for
    // the same permission sets.
    user_save($this->normal_user_alt, array('roles' => $this->normal_user->roles));
    $this->normal_user_alt->roles = $this->normal_user->roles;

    // Enable block caching.
    variable_set('block_cache', TRUE);

    // Enable our test block.
    $edit['blocks[block_test_test_cache][region]'] = 'sidebar_first';
    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
  }

  /**
   * Test DRUPAL_CACHE_PER_ROLE.
   */
  function testCachePerRole() {
    $this->setCacheMode(DRUPAL_CACHE_PER_ROLE);

    // Enable our test block. Set some content for it to display.
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);
    $this->drupalLogin($this->normal_user);
    $this->drupalGet('');
    $this->assertText($current_content, 'Block content displays.');

    // Change the content, but the cached copy should still be served.
    $old_content = $current_content;
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);
    $this->drupalGet('');
    $this->assertText($old_content, 'Block is served from the cache.');

    // Clear the cache and verify that the stale data is no longer there.
    cache_clear_all();
    $this->drupalGet('');
    $this->assertNoText($old_content, 'Block cache clear removes stale cache data.');
    $this->assertText($current_content, 'Fresh block content is displayed after clearing the cache.');

    // Test whether the cached data is served for the correct users.
    $old_content = $current_content;
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);
    $this->drupalLogout();
    $this->drupalGet('');
    $this->assertNoText($old_content, 'Anonymous user does not see content cached per-role for normal user.');

    $this->drupalLogin($this->normal_user_alt);
    $this->drupalGet('');
    $this->assertText($old_content, 'User with the same roles sees per-role cached content.');

    $this->drupalLogin($this->admin_user);
    $this->drupalGet('');
    $this->assertNoText($old_content, 'Admin user does not see content cached per-role for normal user.');

    $this->drupalLogin($this->normal_user);
    $this->drupalGet('');
    $this->assertText($old_content, 'Block is served from the per-role cache.');
  }

  /**
   * Test DRUPAL_CACHE_GLOBAL.
   */
  function testCacheGlobal() {
    $this->setCacheMode(DRUPAL_CACHE_GLOBAL);
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);

    $this->drupalGet('');
    $this->assertText($current_content, 'Block content displays.');

    $old_content = $current_content;
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);

    $this->drupalLogout();
    $this->drupalGet('user');
    $this->assertText($old_content, 'Block content served from global cache.');
  }

  /**
   * Test DRUPAL_NO_CACHE.
   */
  function testNoCache() {
    $this->setCacheMode(DRUPAL_NO_CACHE);
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);

    // If DRUPAL_NO_CACHE has no effect, the next request would be cached.
    $this->drupalGet('');
    $this->assertText($current_content, 'Block content displays.');

    // A cached copy should not be served.
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);
    $this->drupalGet('');
    $this->assertText($current_content, 'DRUPAL_NO_CACHE prevents blocks from being cached.');
  }

  /**
   * Test DRUPAL_CACHE_PER_USER.
   */
  function testCachePerUser() {
    $this->setCacheMode(DRUPAL_CACHE_PER_USER);
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);
    $this->drupalLogin($this->normal_user);

    $this->drupalGet('');
    $this->assertText($current_content, 'Block content displays.');

    $old_content = $current_content;
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);

    $this->drupalGet('');
    $this->assertText($old_content, 'Block is served from per-user cache.');

    $this->drupalLogin($this->normal_user_alt);
    $this->drupalGet('');
    $this->assertText($current_content, 'Per-user block cache is not served for other users.');

    $this->drupalLogin($this->normal_user);
    $this->drupalGet('');
    $this->assertText($old_content, 'Per-user block cache is persistent.');
  }

  /**
   * Test DRUPAL_CACHE_PER_PAGE.
   */
  function testCachePerPage() {
    $this->setCacheMode(DRUPAL_CACHE_PER_PAGE);
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);

    $this->drupalGet('node');
    $this->assertText($current_content, 'Block content displays on the node page.');

    $old_content = $current_content;
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);

    $this->drupalGet('user');
    $this->assertNoText($old_content, 'Block content cached for the node page does not show up for the user page.');
    $this->drupalGet('node');
    $this->assertText($old_content, 'Block content cached for the node page.');
  }

  /**
   * Private helper method to set the test block's cache mode.
   */
  private function setCacheMode($cache_mode) {
    db_update('block')
      ->fields(array('cache' => $cache_mode))
      ->condition('module', 'block_test')
      ->execute();

    $current_mode = db_query("SELECT cache FROM {block} WHERE module = 'block_test'")->fetchField();
    if ($current_mode != $cache_mode) {
      $this->fail(t('Unable to set cache mode to %mode. Current mode: %current_mode', array('%mode' => $cache_mode, '%current_mode' => $current_mode)));
    }
  }
}

/**
 * Test block HTML id validity.
 */
class BlockHTMLIdTestCase extends DrupalWebTestCase {

  public static function getInfo() {
    return array(
      'name' => 'Block HTML id',
      'description' => 'Test block HTML id validity.',
      'group' => 'Block',
    );
  }

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

    // Create an admin user, log in and enable test blocks.
    $this->admin_user = $this->drupalCreateUser(array('administer blocks', 'access administration pages'));
    $this->drupalLogin($this->admin_user);

    // Enable our test block.
    $edit['blocks[block_test_test_html_id][region]'] = 'sidebar_first';
    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));

    // Make sure the block has some content so it will appear
    $current_content = $this->randomName();
    variable_set('block_test_content', $current_content);
  }

  /**
   * Test valid HTML id.
   */
  function testHTMLId() {
    $this->drupalGet('');
    $this->assertRaw('block-block-test-test-html-id', 'HTML id for test block is valid.');
  }
}


/**
 * Unit tests for template_preprocess_block().
 */
class BlockTemplateSuggestionsUnitTest extends DrupalUnitTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Block template suggestions',
      'description' => 'Test the template_preprocess_block() function.',
      'group' => 'Block',
    );
  }

  /**
   * Test if template_preprocess_block() handles the suggestions right.
   */
  function testBlockThemeHookSuggestions() {
    // Define block delta with underscore to be preprocessed
    $block1 = new stdClass();
    $block1->module = 'block';
    $block1->delta = 'underscore_test';
    $block1->region = 'footer';
    $variables1 = array();
    $variables1['elements']['#block'] = $block1;
    $variables1['elements']['#children'] = '';
    template_preprocess_block($variables1);
    $this->assertEqual($variables1['theme_hook_suggestions'], array('block__footer', 'block__block', 'block__block__underscore_test'), 'Found expected block suggestions for delta with underscore');

    // Define block delta with hyphens to be preprocessed. Hyphens should be
    // replaced with underscores.
    $block2 = new stdClass();
    $block2->module = 'block';
    $block2->delta = 'hyphen-test';
    $block2->region = 'footer';
    $variables2 = array();
    $variables2['elements']['#block'] = $block2;
    $variables2['elements']['#children'] = '';
    template_preprocess_block($variables2);
    $this->assertEqual($variables2['theme_hook_suggestions'], array('block__footer', 'block__block', 'block__block__hyphen_test'), 'Hyphens (-) in block delta were replaced by underscore (_)');
  }
}

/**
 * Tests for hook_block_view_MODULE_DELTA_alter().
 */
class BlockViewModuleDeltaAlterWebTest extends DrupalWebTestCase {

  public static function getInfo() {
    return array(
      'name' => 'Block view module delta alter',
      'description' => 'Test the hook_block_view_MODULE_DELTA_alter() hook.',
      'group' => 'Block',
    );
  }

  public function setUp() {
    parent::setUp(array('block_test'));
  }

  /**
   * Tests that the alter hook is called, even if the delta contains a hyphen.
   */
  public function testBlockViewModuleDeltaAlter() {
    $block = new stdClass;
    $block->module = 'block_test';
    $block->delta = 'test_underscore';
    $block->title = '';
    $render_array = _block_render_blocks(array('region' => $block));
    $render = array_pop($render_array);
    $test_underscore = $render->content['#markup'];
    $this->assertEqual($test_underscore, 'hook_block_view_MODULE_DELTA_alter', 'Found expected altered block content for delta with underscore');

    $block = new stdClass;
    $block->module = 'block_test';
    $block->delta = 'test-hyphen';
    $block->title = '';
    $render_array = _block_render_blocks(array('region' => $block));
    $render = array_pop($render_array);
    $test_hyphen = $render->content['#markup'];
    $this->assertEqual($test_hyphen, 'hook_block_view_MODULE_DELTA_alter', 'Hyphens (-) in block delta were replaced by underscore (_)');
  }

}

/**
 * Tests that hidden regions do not inherit blocks when a theme is enabled.
 */
class BlockHiddenRegionTestCase extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Blocks not in hidden region',
      'description' => 'Checks that a newly enabled theme does not inherit blocks to its hidden regions.',
      'group' => 'Block',
    );
  }

  function setUp() {
    parent::setUp(array('block_test'));
  }

  /**
   * Tests that hidden regions do not inherit blocks when a theme is enabled.
   */
  function testBlockNotInHiddenRegion() {
    // Create administrative user.
    $admin_user = $this->drupalCreateUser(array('administer blocks', 'administer themes', 'search content'));
    $this->drupalLogin($admin_user);

    // Enable "block_test_theme" and set it as the default theme.
    $theme = 'block_test_theme';
    theme_enable(array($theme));
    variable_set('theme_default', $theme);
    menu_rebuild();

    // Ensure that "block_test_theme" is set as the default theme.
    $this->drupalGet('admin/structure/block');
    $this->assertText('Block test theme(' . t('active tab') . ')', 'Default local task on blocks admin page is the block test theme.');

    // Ensure that the search form block is displayed.
    $this->drupalGet('');
    $this->assertText('Search form', 'Block was displayed on the front page.');
  }
}

/**
 * Tests that a block assigned to an invalid region triggers the warning.
 */
class BlockInvalidRegionTestCase extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Blocks in invalid regions',
      'description' => 'Checks that an active block assigned to a non-existing region triggers the warning message and is disabled.',
      'group' => 'Block',
    );
  }

  function setUp() {
    parent::setUp(array('block', 'block_test'));
    // Create an admin user.
    $admin_user = $this->drupalCreateUser(array('administer site configuration', 'access administration pages'));
    $this->drupalLogin($admin_user);
  }

  /**
   * Tests that blocks assigned to invalid regions work correctly.
   */
  function testBlockInInvalidRegion() {
    // Enable a test block in the default theme and place it in an invalid region.
    db_merge('block')
      ->key(array(
        'module' => 'block_test',
        'delta' => 'test_html_id',
        'theme' => variable_get('theme_default', 'stark'),
      ))
      ->fields(array(
        'status' => 1,
        'region' => 'invalid_region',
        'cache' => DRUPAL_NO_CACHE,
      ))
      ->execute();

    $warning_message = t('The block %info was assigned to the invalid region %region and has been disabled.', array('%info' => t('Test block html id'), '%region' => 'invalid_region'));

    // Clearing the cache should disable the test block placed in the invalid region.
    $this->drupalPost('admin/config/development/performance', array(), 'Clear all caches');
    $this->assertRaw($warning_message, 'Enabled block was in the invalid region and has been disabled.');

    // Clear the cache to check if the warning message is not triggered.
    $this->drupalPost('admin/config/development/performance', array(), 'Clear all caches');
    $this->assertNoRaw($warning_message, 'Disabled block in the invalid region will not trigger the warning.');

    // Place disabled test block in the invalid region of the default theme.
    db_merge('block')
      ->key(array(
        'module' => 'block_test',
        'delta' => 'test_html_id',
        'theme' => variable_get('theme_default', 'stark'),
      ))
      ->fields(array(
        'region' => 'invalid_region',
        'cache' => DRUPAL_NO_CACHE,
      ))
      ->execute();

    // Clear the cache to check if the warning message is not triggered.
    $this->drupalPost('admin/config/development/performance', array(), 'Clear all caches');
    $this->assertNoRaw($warning_message, 'Disabled block in the invalid region will not trigger the warning.');
  }
}

/**
 * Tests that block rehashing works correctly.
 */
class BlockHashTestCase extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Block rehash',
      'description' => 'Checks _block_rehash() functionality.',
      'group' => 'Block',
    );
  }

  function setUp() {
    parent::setUp(array('block'));
  }

  /**
   * Tests that block rehashing does not write to the database too often.
   */
  function testBlockRehash() {
    // No hook_block_info_alter(), no save.
    $this->doRehash();
    module_enable(array('block_test'), FALSE);
    // Save the new blocks, check that the new blocks exist by checking weight.
    _block_rehash();
    $this->assertWeight(0);
    // Now hook_block_info_alter() exists but no blocks are saved on a second
    // rehash.
    $this->doRehash();
    $this->assertWeight(0);
    // Now hook_block_info_alter() exists and is changing one block which
    // should be saved.
    $GLOBALS['conf']['block_test_info_alter'] = 1;
    $this->doRehash(TRUE);
    $this->assertWeight(10000);
    // Now hook_block_info_alter() exists but already changed the block's
    // weight before, so it should not be saved again.
    $this->doRehash();
    $this->assertWeight(10000);
  }

  /**
   * Performs a block rehash and checks several related assertions.
   *
   * @param $alter_active
   *   Set to TRUE if the block_test module's hook_block_info_alter()
   *   implementation is expected to make a change that results in an existing
   *   block needing to be resaved to the database. Defaults to FALSE.
   */
  function doRehash($alter_active = FALSE) {
    $saves = 0;
    foreach (_block_rehash() as $block) {
      $module = $block['module'];
      $delta = $block['delta'];
      if ($alter_active && $module == 'block_test' && $delta == 'test_html_id') {
        $this->assertFalse(empty($block['saved']), "$module $delta saved");
        $saves++;
      }
      else {
        $this->assertTrue(empty($block['saved']), "$module $delta not saved");
      }
    }
    $this->assertEqual($alter_active, $saves);
  }

  /**
   * Asserts that the block_test module's block has a given weight.
   *
   * @param $weight
   *   The expected weight.
   */
  function assertWeight($weight) {
    $db_weight = db_query('SELECT weight FROM {block} WHERE module = :module AND delta = :delta', array(':module' => 'block_test', ':delta' => 'test_html_id'))->fetchField();
    // By casting to string the assert fails on FALSE.
    $this->assertIdentical((string) $db_weight, (string) $weight);
  }
}