diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php index 381e891..86d4740 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php @@ -54,23 +54,34 @@ function setUp() { // Enable dummy module that implements hook_menu. parent::setUp(); - // Explicitly set the default and admin themes. - $this->default_theme = 'bartik'; - $this->admin_theme = 'seven'; - $this->alternate_theme = 'stark'; - theme_enable(array($this->default_theme)); - \Drupal::config('system.theme') - ->set('default', $this->default_theme) - ->set('admin', $this->admin_theme) - ->save(); - theme_disable(array($this->alternate_theme)); $this->drupalPlaceBlock('system_menu_block:tools'); } /** + * Tests menu integration. + */ + public function testMenuIntegration() { + $this->_testTitleMenuCallback(); + $this->_testMenuSetItem(); + $this->_testMenuOptionalPlaceholders(); + $this->_testMenuOnRoute(); + $this->_testMenuHidden(); + $this->_testMenuGetItemNoAncestors(); + $this->_testMenuName(); + $this->_testMenuItemTitlesCases(); + $this->_testMenuLinkMaintain(); + $this->_testMenuLinkOptions(); + $this->_testMenuLoadArgumentsInheritance(); + $this->_testMenuItemHooks(); + $this->_testDescriptionMenuItems(); + $this->_testHookMenuIntegration(); + $this->_testExoticPath(); + } + + /** * Test local tasks with route placeholders. */ - public function testHookMenuIntegration() { + protected function _testHookMenuIntegration() { // Generate base path with random argument. $base_path = 'foo/' . $this->randomName(8); $this->drupalGet($base_path); @@ -87,7 +98,7 @@ public function testHookMenuIntegration() { /** * Test title callback set to FALSE. */ - function testTitleCallbackFalse() { + protected function _testTitleCallbackFalse() { $this->drupalGet('test-page'); $this->assertText('A title with @placeholder', 'Raw text found on the page'); $this->assertNoText(t('A title with @placeholder', array('@placeholder' => 'some other text')), 'Text with placeholder substitutions not found.'); @@ -96,7 +107,7 @@ function testTitleCallbackFalse() { /** * Tests page title of MENU_CALLBACKs. */ - function testTitleMenuCallback() { + protected function _testTitleMenuCallback() { // Verify that the menu router item title is not visible. $this->drupalGet(''); $this->assertNoText(t('Menu Callback Title')); @@ -108,7 +119,7 @@ function testTitleMenuCallback() { /** * Tests menu item descriptions. */ - function testDescriptionMenuItems() { + protected function _testDescriptionMenuItems() { // Verify that the menu router item title is output as page title. $this->drupalGet('menu_callback_description'); $this->assertText(t('Menu item description text')); @@ -116,162 +127,9 @@ function testDescriptionMenuItems() { } /** - * Test the theme callback when it is set to use an administrative theme. - */ - function testThemeCallbackAdministrative() { - theme_enable(array($this->admin_theme)); - $this->drupalGet('menu-test/theme-callback/use-admin-theme'); - $this->assertText('Custom theme: seven. Actual theme: seven.', 'The administrative theme can be correctly set in a theme callback.'); - $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page."); - } - - /** - * Test that the theme callback is properly inherited. - */ - function testThemeCallbackInheritance() { - theme_enable(array($this->admin_theme)); - $this->drupalGet('menu-test/theme-callback/use-admin-theme/inheritance'); - $this->assertText('Custom theme: seven. Actual theme: seven. Theme callback inheritance is being tested.', 'Theme callback inheritance correctly uses the administrative theme.'); - $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page."); - } - - /** - * Test path containing "exotic" characters. - */ - function testExoticPath() { - $path = "menu-test/ -._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters. - "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string. - "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets. - $this->drupalGet($path); - $this->assertRaw('This is menu_test_callback().'); - } - - /** - * Test the theme callback when the site is in maintenance mode. - */ - function testThemeCallbackMaintenanceMode() { - $this->container->get('state')->set('system.maintenance_mode', TRUE); - theme_enable(array($this->admin_theme)); - - // For a regular user, the fact that the site is in maintenance mode means - // we expect the theme callback system to be bypassed entirely. - $this->drupalGet('menu-test/theme-callback/use-admin-theme'); - $this->assertRaw('bartik/css/style.css', "The maintenance theme's CSS appears on the page."); - - // An administrator, however, should continue to see the requested theme. - $admin_user = $this->drupalCreateUser(array('access site in maintenance mode')); - $this->drupalLogin($admin_user); - $this->drupalGet('menu-test/theme-callback/use-admin-theme'); - $this->assertText('Custom theme: seven. Actual theme: seven.', 'The theme callback system is correctly triggered for an administrator when the site is in maintenance mode.'); - $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page."); - - $this->container->get('state')->set('system.maintenance_mode', FALSE); - } - - /** - * Make sure the maintenance mode can be bypassed using an EventSubscriber. - * - * @see \Drupal\menu_test\EventSubscriber\MaintenanceModeSubscriber::onKernelRequestMaintenance(). - */ - function testMaintenanceModeLoginPaths() { - $this->container->get('state')->set('system.maintenance_mode', TRUE); - - $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => \Drupal::config('system.site')->get('name'))); - $this->drupalGet('test-page'); - $this->assertText($offline_message); - $this->drupalGet('menu_login_callback'); - $this->assertText('This is TestControllers::testLogin.', 'Maintenance mode can be bypassed using an event subscriber.'); - - $this->container->get('state')->set('system.maintenance_mode', FALSE); - } - - /** - * Test that an authenticated user hitting 'user/login' gets redirected to - * 'user' and 'user/register' gets redirected to the user edit page. - */ - function testAuthUserUserLogin() { - $web_user = $this->drupalCreateUser(array()); - $this->drupalLogin($web_user); - - $this->drupalGet('user/login'); - // Check that we got to 'user'. - $this->assertTrue($this->url == url('user/' . $this->loggedInUser->id(), array('absolute' => TRUE)), "Logged-in user redirected to user on accessing user/login"); - - // user/register should redirect to user/UID/edit. - $this->drupalGet('user/register'); - $this->assertTrue($this->url == url('user/' . $this->loggedInUser->id() . '/edit', array('absolute' => TRUE)), "Logged-in user redirected to user/UID/edit on accessing user/register"); - } - - /** - * Test the theme callback when it is set to use an optional theme. - */ - function testThemeCallbackOptionalTheme() { - // Request a theme that is not enabled. - $this->drupalGet('menu-test/theme-callback/use-stark-theme'); - $this->assertText('Custom theme: NONE. Actual theme: bartik.', 'The theme callback system falls back on the default theme when a theme that is not enabled is requested.'); - $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page."); - - // Now enable the theme and request it again. - theme_enable(array($this->alternate_theme)); - $this->drupalGet('menu-test/theme-callback/use-stark-theme'); - $this->assertText('Custom theme: stark. Actual theme: stark.', 'The theme callback system uses an optional theme once it has been enabled.'); - $this->assertRaw('stark/css/layout.css', "The optional theme's CSS appears on the page."); - } - - /** - * Test the theme callback when it is set to use a theme that does not exist. - */ - function testThemeCallbackFakeTheme() { - $this->drupalGet('menu-test/theme-callback/use-fake-theme'); - $this->assertText('Custom theme: NONE. Actual theme: bartik.', 'The theme callback system falls back on the default theme when a theme that does not exist is requested.'); - $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page."); - } - - /** - * Test the theme callback when no theme is requested. - */ - function testThemeCallbackNoThemeRequested() { - $this->drupalGet('menu-test/theme-callback/no-theme-requested'); - $this->assertText('Custom theme: NONE. Actual theme: bartik.', 'The theme callback system falls back on the default theme when no theme is requested.'); - $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page."); - } - - /** - * Test that hook_custom_theme() can control the theme of a page. - */ - function testHookCustomTheme() { - // Trigger hook_custom_theme() to dynamically request the Stark theme for - // the requested page. - \Drupal::state()->set('menu_test.hook_custom_theme_name', $this->alternate_theme); - theme_enable(array($this->alternate_theme, $this->admin_theme)); - - // Visit a page that does not implement a theme callback. The above request - // should be honored. - $this->drupalGet('menu-test/no-theme-callback'); - $this->assertText('Custom theme: stark. Actual theme: stark.', 'The result of hook_custom_theme() is used as the theme for the current page.'); - $this->assertRaw('stark/css/layout.css', "The Stark theme's CSS appears on the page."); - } - - /** - * Test that the theme callback wins out over hook_custom_theme(). - */ - function testThemeCallbackHookCustomTheme() { - // Trigger hook_custom_theme() to dynamically request the Stark theme for - // the requested page. - \Drupal::state()->set('menu_test.hook_custom_theme_name', $this->alternate_theme); - theme_enable(array($this->alternate_theme, $this->admin_theme)); - - // The menu "theme callback" should take precedence over a value set in - // hook_custom_theme(). - $this->drupalGet('menu-test/theme-callback/use-admin-theme'); - $this->assertText('Custom theme: seven. Actual theme: seven.', 'The result of hook_custom_theme() does not override what was set in a theme callback.'); - $this->assertRaw('seven/style.css', "The Seven theme's CSS appears on the page."); - } - - /** * Tests for menu_link_maintain(). */ - function testMenuLinkMaintain() { + protected function _testMenuLinkMaintain() { $admin_user = $this->drupalCreateUser(array('access content', 'administer site configuration')); $this->drupalLogin($admin_user); @@ -317,7 +175,7 @@ function testMenuLinkMaintain() { /** * Tests for menu_name parameter for hook_menu(). */ - function testMenuName() { + protected function _testMenuName() { $admin_user = $this->drupalCreateUser(array('administer site configuration')); $this->drupalLogin($admin_user); @@ -339,7 +197,7 @@ function testMenuName() { /** * Tests for menu hierarchy. */ - function testMenuHierarchy() { + protected function _testMenuHierarchy() { $parent_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu-test/hierarchy/parent')); $parent_link = reset($parent_links); $child_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu-test/hierarchy/parent/child')); @@ -354,7 +212,7 @@ function testMenuHierarchy() { /** * Tests menu link depth and parents of local tasks and menu callbacks. */ - function testMenuHidden() { + protected function _testMenuHidden() { // Verify links for one dynamic argument. $query = \Drupal::entityQuery('menu_link') ->condition('router_path', 'menu-test/hidden/menu', 'STARTS_WITH') @@ -451,7 +309,7 @@ function testMenuHidden() { /** * Test menu_get_item() with empty ancestors. */ - function testMenuGetItemNoAncestors() { + protected function _testMenuGetItemNoAncestors() { \Drupal::state()->set('menu.masks', array()); $this->drupalGet(''); } @@ -459,7 +317,7 @@ function testMenuGetItemNoAncestors() { /** * Test menu_set_item(). */ - function testMenuSetItem() { + protected function _testMenuSetItem() { $item = menu_get_item('test-page'); $this->assertEqual($item['path'], 'test-page', "Path from menu_get_item('test-page') is equal to 'test-page'", 'menu'); @@ -476,7 +334,7 @@ function testMenuSetItem() { /** * Test menu maintenance hooks. */ - function testMenuItemHooks() { + protected function _testMenuItemHooks() { // Create an item. menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/4', 'Menu link #4'); $this->assertEqual(menu_test_static_variable(), 'insert', 'hook_menu_link_insert() fired correctly'); @@ -491,7 +349,7 @@ function testMenuItemHooks() { /** * Test menu link 'options' storage and rendering. */ - function testMenuLinkOptions() { + protected function _testMenuLinkOptions() { // Create a menu link with options. $menu_link = entity_create('menu_link', array( 'link_title' => 'Menu link options test', @@ -518,7 +376,7 @@ function testMenuLinkOptions() { * Tests the possible ways to set the title for menu items. * Also tests that menu item titles work with string overrides. */ - function testMenuItemTitlesCases() { + protected function _testMenuItemTitlesCases() { // Build array with string overrides. $test_data = array( @@ -540,7 +398,7 @@ function testMenuItemTitlesCases() { * Get a URL and assert the title given a case number. If override is true, * the title is asserted to begin with "Alternative". */ - private function menuItemTitlesCasesHelper($case_no, $override = FALSE) { + protected function menuItemTitlesCasesHelper($case_no, $override = FALSE) { $this->drupalGet('menu-title-test/case' . $case_no); $this->assertResponse(200); $asserted_title = $override ? 'Alternative example title - Case ' . $case_no : 'Example title - Case ' . $case_no; @@ -557,7 +415,7 @@ protected function menuLoadRouter($router_path) { /** * Tests inheritance of 'load arguments'. */ - function testMenuLoadArgumentsInheritance() { + protected function _testMenuLoadArgumentsInheritance() { $expected = array( 'menu-test/arguments/%/%' => array( 2 => array('menu_test_argument_load' => array(3)), @@ -608,7 +466,7 @@ function testMenuLoadArgumentsInheritance() { /** * Test menu links that have optional placeholders. */ - public function testMenuOptionalPlaceholders() { + protected function _testMenuOptionalPlaceholders() { $this->drupalGet('menu-test/optional'); $this->assertResponse(200); $this->assertText('Sometimes there is no placeholder.'); @@ -621,7 +479,7 @@ public function testMenuOptionalPlaceholders() { /** * Tests a menu on a router page. */ - public function testMenuOnRoute() { + protected function _testMenuOnRoute() { \Drupal::moduleHandler()->install(array('router_test')); \Drupal::service('router.builder')->rebuild(); @@ -633,4 +491,201 @@ public function testMenuOnRoute() { $this->assertLinkByHref('menu-title-test/case4'); } + /** + * Test path containing "exotic" characters. + */ + function _testExoticPath() { + $path = "menu-test/ -._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters. + "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string. + "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets. + $this->drupalGet($path); + $this->assertRaw('This is menu_test_callback().'); + } + + /** + * Make sure the maintenance mode can be bypassed using an EventSubscriber. + * + * @see \Drupal\menu_test\EventSubscriber\MaintenanceModeSubscriber::onKernelRequestMaintenance(). + */ + public function testMaintenanceModeLoginPaths() { + $this->container->get('state')->set('system.maintenance_mode', TRUE); + + $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => \Drupal::config('system.site')->get('name'))); + $this->drupalGet('test-page'); + $this->assertText($offline_message); + $this->drupalGet('menu_login_callback'); + $this->assertText('This is TestControllers::testLogin.', 'Maintenance mode can be bypassed using an event subscriber.'); + + $this->container->get('state')->set('system.maintenance_mode', FALSE); + } + + /** + * Test that an authenticated user hitting 'user/login' gets redirected to + * 'user' and 'user/register' gets redirected to the user edit page. + */ + public function testAuthUserUserLogin() { + $web_user = $this->drupalCreateUser(array()); + $this->drupalLogin($web_user); + + $this->drupalGet('user/login'); + // Check that we got to 'user'. + $this->assertTrue($this->url == url('user/' . $this->loggedInUser->id(), array('absolute' => TRUE)), "Logged-in user redirected to user on accessing user/login"); + + // user/register should redirect to user/UID/edit. + $this->drupalGet('user/register'); + $this->assertTrue($this->url == url('user/' . $this->loggedInUser->id() . '/edit', array('absolute' => TRUE)), "Logged-in user redirected to user/UID/edit on accessing user/register"); + } + + /** + * Tests theme integration. + */ + public function testThemeIntegration() { + $this->initializeTestThemeConfiguration(); + $this->_testThemeCallbackMaintenanceMode(); + + $this->initializeTestThemeConfiguration(); + $this->_testThemeCallbackFakeTheme(); + + $this->initializeTestThemeConfiguration(); + $this->_testHookCustomTheme(); + + $this->initializeTestThemeConfiguration(); + $this->_testThemeCallbackHookCustomTheme(); + + $this->initializeTestThemeConfiguration(); + $this->_testThemeCallbackAdministrative(); + + $this->initializeTestThemeConfiguration(); + $this->_testThemeCallbackInheritance(); + + $this->initializeTestThemeConfiguration(); + $this->_testThemeCallbackNoThemeRequested(); + + $this->initializeTestThemeConfiguration(); + $this->_testThemeCallbackOptionalTheme(); + } + + /** + * Explicitly set the default and admin themes. + */ + protected function initializeTestThemeConfiguration() { + $this->default_theme = 'bartik'; + $this->admin_theme = 'seven'; + $this->alternate_theme = 'stark'; + theme_enable(array($this->default_theme)); + \Drupal::config('system.theme') + ->set('default', $this->default_theme) + ->set('admin', $this->admin_theme) + ->save(); + theme_disable(array($this->alternate_theme)); + } + + /** + * Test the theme callback when it is set to use an administrative theme. + */ + protected function _testThemeCallbackAdministrative() { + theme_enable(array($this->admin_theme)); + $this->drupalGet('menu-test/theme-callback/use-admin-theme'); + $this->assertText('Custom theme: seven. Actual theme: seven.', 'The administrative theme can be correctly set in a theme callback.'); + $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page."); + } + + /** + * Test that the theme callback is properly inherited. + */ + protected function _testThemeCallbackInheritance() { + theme_enable(array($this->admin_theme)); + $this->drupalGet('menu-test/theme-callback/use-admin-theme/inheritance'); + $this->assertText('Custom theme: seven. Actual theme: seven. Theme callback inheritance is being tested.', 'Theme callback inheritance correctly uses the administrative theme.'); + $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page."); + } + + /** + * Test the theme callback when the site is in maintenance mode. + */ + protected function _testThemeCallbackMaintenanceMode() { + $this->container->get('state')->set('system.maintenance_mode', TRUE); + theme_enable(array($this->admin_theme)); + + // For a regular user, the fact that the site is in maintenance mode means + // we expect the theme callback system to be bypassed entirely. + $this->drupalGet('menu-test/theme-callback/use-admin-theme'); + $this->assertRaw('bartik/css/style.css', "The maintenance theme's CSS appears on the page."); + + // An administrator, however, should continue to see the requested theme. + $admin_user = $this->drupalCreateUser(array('access site in maintenance mode')); + $this->drupalLogin($admin_user); + $this->drupalGet('menu-test/theme-callback/use-admin-theme'); + $this->assertText('Custom theme: seven. Actual theme: seven.', 'The theme callback system is correctly triggered for an administrator when the site is in maintenance mode.'); + $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page."); + + $this->container->get('state')->set('system.maintenance_mode', FALSE); + } + + /** + * Test the theme callback when it is set to use an optional theme. + */ + protected function _testThemeCallbackOptionalTheme() { + // Request a theme that is not enabled. + $this->drupalGet('menu-test/theme-callback/use-stark-theme'); + $this->assertText('Custom theme: NONE. Actual theme: bartik.', 'The theme callback system falls back on the default theme when a theme that is not enabled is requested.'); + $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page."); + + // Now enable the theme and request it again. + theme_enable(array($this->alternate_theme)); + $this->drupalGet('menu-test/theme-callback/use-stark-theme'); + $this->assertText('Custom theme: stark. Actual theme: stark.', 'The theme callback system uses an optional theme once it has been enabled.'); + $this->assertRaw('stark/css/layout.css', "The optional theme's CSS appears on the page."); + } + + /** + * Test the theme callback when it is set to use a theme that does not exist. + */ + protected function _testThemeCallbackFakeTheme() { + $this->drupalGet('menu-test/theme-callback/use-fake-theme'); + $this->assertText('Custom theme: NONE. Actual theme: bartik.', 'The theme callback system falls back on the default theme when a theme that does not exist is requested.'); + $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page."); + } + + /** + * Test the theme callback when no theme is requested. + */ + protected function _testThemeCallbackNoThemeRequested() { + $this->drupalGet('menu-test/theme-callback/no-theme-requested'); + $this->assertText('Custom theme: NONE. Actual theme: bartik.', 'The theme callback system falls back on the default theme when no theme is requested.'); + $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page."); + } + + /** + * Test that hook_custom_theme() can control the theme of a page. + */ + protected function _testHookCustomTheme() { + // Trigger hook_custom_theme() to dynamically request the Stark theme for + // the requested page. + \Drupal::state()->set('menu_test.hook_custom_theme_name', $this->alternate_theme); + theme_enable(array($this->alternate_theme, $this->admin_theme)); + + // Visit a page that does not implement a theme callback. The above request + // should be honored. + $this->drupalGet('menu-test/no-theme-callback'); + $this->assertText('Custom theme: stark. Actual theme: stark.', 'The result of hook_custom_theme() is used as the theme for the current page.'); + $this->assertRaw('stark/css/layout.css', "The Stark theme's CSS appears on the page."); + } + + /** + * Test that the theme callback wins out over hook_custom_theme(). + */ + protected function _testThemeCallbackHookCustomTheme() { + // Trigger hook_custom_theme() to dynamically request the Stark theme for + // the requested page. + \Drupal::state()->set('menu_test.hook_custom_theme_name', $this->alternate_theme); + theme_enable(array($this->alternate_theme, $this->admin_theme)); + + // The menu "theme callback" should take precedence over a value set in + // hook_custom_theme(). + $this->drupalGet('menu-test/theme-callback/use-admin-theme'); + $this->assertText('Custom theme: seven. Actual theme: seven.', 'The result of hook_custom_theme() does not override what was set in a theme callback.'); + $this->assertRaw('seven/style.css', "The Seven theme's CSS appears on the page."); + } + }