diff -r 07239de796bb -r e756a8c72c3d cms/drupal/modules/simpletest/tests/theme.test --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cms/drupal/modules/simpletest/tests/theme.test Fri Sep 08 12:04:06 2017 +0200 @@ -0,0 +1,679 @@ + 'Theme API', + 'description' => 'Test low-level theme functions.', + 'group' => 'Theme', + ); + } + + function setUp() { + parent::setUp('theme_test'); + theme_enable(array('test_theme')); + } + + /** + * Test function theme_get_suggestions() for SA-CORE-2009-003. + */ + function testThemeSuggestions() { + // Set the front page as something random otherwise the CLI + // test runner fails. + variable_set('site_frontpage', 'nobody-home'); + $args = array('node', '1', 'edit'); + $suggestions = theme_get_suggestions($args, 'page'); + $this->assertEqual($suggestions, array('page__node', 'page__node__%', 'page__node__1', 'page__node__edit'), 'Found expected node edit page suggestions'); + // Check attack vectors. + $args = array('node', '\\1'); + $suggestions = theme_get_suggestions($args, 'page'); + $this->assertEqual($suggestions, array('page__node', 'page__node__%', 'page__node__1'), 'Removed invalid \\ from suggestions'); + $args = array('node', '1/'); + $suggestions = theme_get_suggestions($args, 'page'); + $this->assertEqual($suggestions, array('page__node', 'page__node__%', 'page__node__1'), 'Removed invalid / from suggestions'); + $args = array('node', "1\0"); + $suggestions = theme_get_suggestions($args, 'page'); + $this->assertEqual($suggestions, array('page__node', 'page__node__%', 'page__node__1'), 'Removed invalid \\0 from suggestions'); + // Define path with hyphens to be used to generate suggestions. + $args = array('node', '1', 'hyphen-path'); + $result = array('page__node', 'page__node__%', 'page__node__1', 'page__node__hyphen_path'); + $suggestions = theme_get_suggestions($args, 'page'); + $this->assertEqual($suggestions, $result, 'Found expected page suggestions for paths containing hyphens.'); + } + + /** + * Ensures preprocess functions run even for suggestion implementations. + * + * The theme hook used by this test has its base preprocess function in a + * separate file, so this test also ensures that that file is correctly loaded + * when needed. + */ + function testPreprocessForSuggestions() { + // Test with both an unprimed and primed theme registry. + drupal_theme_rebuild(); + for ($i = 0; $i < 2; $i++) { + $this->drupalGet('theme-test/suggestion'); + $this->assertText('Theme hook implementor=test_theme_theme_test__suggestion(). Foo=template_preprocess_theme_test', 'Theme hook suggestion ran with data available from a preprocess function for the base hook.'); + } + } + + /** + * Ensure page-front template suggestion is added when on front page. + */ + function testFrontPageThemeSuggestion() { + $q = $_GET['q']; + // Set $_GET['q'] to node because theme_get_suggestions() will query it to + // see if we are on the front page. + $_GET['q'] = variable_get('site_frontpage', 'node'); + $suggestions = theme_get_suggestions(explode('/', $_GET['q']), 'page'); + // Set it back to not annoy the batch runner. + $_GET['q'] = $q; + $this->assertTrue(in_array('page__front', $suggestions), 'Front page template was suggested.'); + } + + /** + * Ensures theme hook_*_alter() implementations can run before anything is rendered. + */ + function testAlter() { + $this->drupalGet('theme-test/alter'); + $this->assertText('The altered data is test_theme_theme_test_alter_alter was invoked.', 'The theme was able to implement an alter hook during page building before anything was rendered.'); + } + + /** + * Ensures a theme's .info file is able to override a module CSS file from being added to the page. + * + * @see test_theme.info + */ + function testCSSOverride() { + // Reuse the same page as in testPreprocessForSuggestions(). We're testing + // what is output to the HTML HEAD based on what is in a theme's .info file, + // so it doesn't matter what page we get, as long as it is themed with the + // test theme. First we test with CSS aggregation disabled. + variable_set('preprocess_css', 0); + $this->drupalGet('theme-test/suggestion'); + $this->assertNoText('system.base.css', 'The theme\'s .info file is able to override a module CSS file from being added to the page.'); + + // Also test with aggregation enabled, simply ensuring no PHP errors are + // triggered during drupal_build_css_cache() when a source file doesn't + // exist. Then allow remaining tests to continue with aggregation disabled + // by default. + variable_set('preprocess_css', 1); + $this->drupalGet('theme-test/suggestion'); + variable_set('preprocess_css', 0); + } + + /** + * Ensures the theme registry is rebuilt when modules are disabled/enabled. + */ + function testRegistryRebuild() { + $this->assertIdentical(theme('theme_test_foo', array('foo' => 'a')), 'a', 'The theme registry contains theme_test_foo.'); + + module_disable(array('theme_test'), FALSE); + $this->assertIdentical(theme('theme_test_foo', array('foo' => 'b')), '', 'The theme registry does not contain theme_test_foo, because the module is disabled.'); + + module_enable(array('theme_test'), FALSE); + $this->assertIdentical(theme('theme_test_foo', array('foo' => 'c')), 'c', 'The theme registry contains theme_test_foo again after re-enabling the module.'); + } + + /** + * Test the list_themes() function. + */ + function testListThemes() { + $themes = list_themes(); + // Check if drupal_theme_access() retrieves enabled themes properly from list_themes(). + $this->assertTrue(drupal_theme_access('test_theme'), 'Enabled theme detected'); + // Check if list_themes() returns disabled themes. + $this->assertTrue(array_key_exists('test_basetheme', $themes), 'Disabled theme detected'); + // Check for base theme and subtheme lists. + $base_theme_list = array('test_basetheme' => 'Theme test base theme'); + $sub_theme_list = array('test_subtheme' => 'Theme test subtheme'); + $this->assertIdentical($themes['test_basetheme']->sub_themes, $sub_theme_list, 'Base theme\'s object includes list of subthemes.'); + $this->assertIdentical($themes['test_subtheme']->base_themes, $base_theme_list, 'Subtheme\'s object includes list of base themes.'); + // Check for theme engine in subtheme. + $this->assertIdentical($themes['test_subtheme']->engine, 'phptemplate', 'Subtheme\'s object includes the theme engine.'); + // Check for theme engine prefix. + $this->assertIdentical($themes['test_basetheme']->prefix, 'phptemplate', 'Base theme\'s object includes the theme engine prefix.'); + $this->assertIdentical($themes['test_subtheme']->prefix, 'phptemplate', 'Subtheme\'s object includes the theme engine prefix.'); + } + + /** + * Test the theme_get_setting() function. + */ + function testThemeGetSetting() { + $GLOBALS['theme_key'] = 'test_theme'; + $this->assertIdentical(theme_get_setting('theme_test_setting'), 'default value', 'theme_get_setting() uses the default theme automatically.'); + $this->assertNotEqual(theme_get_setting('subtheme_override', 'test_basetheme'), theme_get_setting('subtheme_override', 'test_subtheme'), 'Base theme\'s default settings values can be overridden by subtheme.'); + $this->assertIdentical(theme_get_setting('basetheme_only', 'test_subtheme'), 'base theme value', 'Base theme\'s default settings values are inherited by subtheme.'); + } + + /** + * Test the drupal_add_region_content() function. + */ + function testDrupalAddRegionContent() { + $this->drupalGet('theme-test/drupal-add-region-content'); + $this->assertText('Hello'); + $this->assertText('World'); + } +} + +/** + * Unit tests for theme_table(). + */ +class ThemeTableTestCase extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Theme Table', + 'description' => 'Tests built-in theme functions.', + 'group' => 'Theme', + ); + } + + /** + * Tableheader.js provides 'sticky' table headers, and is included by default. + */ + function testThemeTableStickyHeaders() { + $header = array('one', 'two', 'three'); + $rows = array(array(1,2,3), array(4,5,6), array(7,8,9)); + $this->content = theme('table', array('header' => $header, 'rows' => $rows)); + $js = drupal_add_js(); + $this->assertTrue(isset($js['misc/tableheader.js']), 'tableheader.js was included when $sticky = TRUE.'); + $this->assertRaw('sticky-enabled', 'Table has a class of sticky-enabled when $sticky = TRUE.'); + drupal_static_reset('drupal_add_js'); + } + + /** + * If $sticky is FALSE, no tableheader.js should be included. + */ + function testThemeTableNoStickyHeaders() { + $header = array('one', 'two', 'three'); + $rows = array(array(1,2,3), array(4,5,6), array(7,8,9)); + $attributes = array(); + $caption = NULL; + $colgroups = array(); + $this->content = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => $attributes, 'caption' => $caption, 'colgroups' => $colgroups, 'sticky' => FALSE)); + $js = drupal_add_js(); + $this->assertFalse(isset($js['misc/tableheader.js']), 'tableheader.js was not included because $sticky = FALSE.'); + $this->assertNoRaw('sticky-enabled', 'Table does not have a class of sticky-enabled because $sticky = FALSE.'); + drupal_static_reset('drupal_add_js'); + } + + /** + * Tests that the table header is printed correctly even if there are no rows, + * and that the empty text is displayed correctly. + */ + function testThemeTableWithEmptyMessage() { + $header = array( + t('Header 1'), + array( + 'data' => t('Header 2'), + 'colspan' => 2, + ), + ); + $this->content = theme('table', array('header' => $header, 'rows' => array(), 'empty' => t('No strings available.'))); + $this->assertRaw('No strings available.', 'Correct colspan was set on empty message.'); + $this->assertRaw('Header 1', 'Table header was printed.'); + } + + /** + * Tests that the 'no_striping' option works correctly. + */ + function testThemeTableWithNoStriping() { + $rows = array( + array( + 'data' => array(1), + 'no_striping' => TRUE, + ), + ); + $this->content = theme('table', array('rows' => $rows)); + $this->assertNoRaw('class="odd"', 'Odd/even classes were not added because $no_striping = TRUE.'); + $this->assertNoRaw('no_striping', 'No invalid no_striping HTML attribute was printed.'); + } +} + +/** + * Unit tests for theme_item_list(). + */ +class ThemeItemListUnitTest extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Theme item list', + 'description' => 'Test the theme_item_list() function.', + 'group' => 'Theme', + ); + } + + /** + * Test item list rendering. + */ + function testItemList() { + $items = array('a', array('data' => 'b', 'children' => array('c' => 'c', 'd' => 'd', 'e' => 'e')), 'f'); + $expected = '
'; + $output = theme('item_list', array('items' => $items)); + $this->assertIdentical($expected, $output, 'Item list is rendered correctly.'); + } +} + +/** + * Unit tests for theme_links(). + */ +class ThemeLinksTest extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Links', + 'description' => 'Test the theme_links() function and rendering groups of links.', + 'group' => 'Theme', + ); + } + + /** + * Test the use of drupal_pre_render_links() on a nested array of links. + */ + function testDrupalPreRenderLinks() { + // Define the base array to be rendered, containing a variety of different + // kinds of links. + $base_array = array( + '#theme' => 'links', + '#pre_render' => array('drupal_pre_render_links'), + '#links' => array( + 'parent_link' => array( + 'title' => 'Parent link original', + 'href' => 'parent-link-original', + ), + ), + 'first_child' => array( + '#theme' => 'links', + '#links' => array( + // This should be rendered if 'first_child' is rendered separately, + // but ignored if the parent is being rendered (since it duplicates + // one of the parent's links). + 'parent_link' => array( + 'title' => 'Parent link copy', + 'href' => 'parent-link-copy', + ), + // This should always be rendered. + 'first_child_link' => array( + 'title' => 'First child link', + 'href' => 'first-child-link', + ), + ), + ), + // This should always be rendered as part of the parent. + 'second_child' => array( + '#theme' => 'links', + '#links' => array( + 'second_child_link' => array( + 'title' => 'Second child link', + 'href' => 'second-child-link', + ), + ), + ), + // This should never be rendered, since the user does not have access to + // it. + 'third_child' => array( + '#theme' => 'links', + '#links' => array( + 'third_child_link' => array( + 'title' => 'Third child link', + 'href' => 'third-child-link', + ), + ), + '#access' => FALSE, + ), + ); + + // Start with a fresh copy of the base array, and try rendering the entire + // thing. We expect a single