drupal/modules/simpletest/tests/menu.test

486 lines
23 KiB
Plaintext

<?php
// $Id$
/**
* @file
* Provides SimpleTests for menu.inc.
*/
class MenuRouterTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Menu router',
'description' => 'Tests menu router and hook_menu() functionality.',
'group' => 'Menu',
);
}
function setUp() {
// Enable dummy module that implements hook_menu.
parent::setUp('menu_test');
// Make the tests below more robust by explicitly setting the default theme
// and administrative theme that they expect.
variable_set('theme_default', 'garland');
variable_set('admin_theme', 'seven');
}
/**
* Test title callback set to FALSE.
*/
function testTitleCallbackFalse() {
$this->drupalGet('node');
$this->assertText('A title with @placeholder', t('Raw text found on the page'));
$this->assertNoText(t('A title with @placeholder', array('@placeholder' => 'some other text')), t('Text with placeholder substitutions not found.'));
}
/**
* Test the theme callback when it is set to use an administrative theme.
*/
function testThemeCallbackAdministrative() {
$this->drupalGet('menu-test/theme-callback/use-admin-theme');
$this->assertText('Custom theme: seven. Actual theme: seven.', t('The administrative theme can be correctly set in a theme callback.'));
$this->assertRaw('seven/style.css', t("The administrative theme's CSS appears on the page."));
}
/**
* Test that the theme callback is properly inherited.
*/
function testThemeCallbackInheritance() {
$this->drupalGet('menu-test/theme-callback/use-admin-theme/inheritance');
$this->assertText('Custom theme: seven. Actual theme: seven. Theme callback inheritance is being tested.', t('Theme callback inheritance correctly uses the administrative theme.'));
$this->assertRaw('seven/style.css', t("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() {
variable_set('maintenance_mode', TRUE);
// 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('garland/style.css', t("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.', t('The theme callback system is correctly triggered for an administrator when the site is in maintenance mode.'));
$this->assertRaw('seven/style.css', t("The administrative theme's CSS appears on the page."));
}
/**
* 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: garland.', t('The theme callback system falls back on the default theme when a theme that is not enabled is requested.'));
$this->assertRaw('garland/style.css', t("The default theme's CSS appears on the page."));
// Now enable the theme and request it again.
theme_enable(array('stark'));
$this->drupalGet('menu-test/theme-callback/use-stark-theme');
$this->assertText('Custom theme: stark. Actual theme: stark.', t('The theme callback system uses an optional theme once it has been enabled.'));
$this->assertRaw('stark/layout.css', t("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: garland.', t('The theme callback system falls back on the default theme when a theme that does not exist is requested.'));
$this->assertRaw('garland/style.css', t("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: garland.', t('The theme callback system falls back on the default theme when no theme is requested.'));
$this->assertRaw('garland/style.css', t("The default theme's CSS appears on the page."));
}
/**
* Test that the result of hook_custom_theme() overrides the theme callback.
*/
function testHookCustomTheme() {
// Trigger hook_custom_theme() to dynamically request the Stark theme for
// the requested page.
variable_set('menu_test_hook_custom_theme_name', 'stark');
// Request a page whose theme callback returns the Seven theme. Since Stark
// is not a currently enabled theme, our above request should be ignored,
// and Seven should still be used.
$this->drupalGet('menu-test/theme-callback/use-admin-theme');
$this->assertText('Custom theme: seven. Actual theme: seven.', t('The result of hook_custom_theme() does not override a theme callback when it returns a theme that is not enabled.'));
$this->assertRaw('seven/style.css', t("The Seven theme's CSS appears on the page."));
// Now enable the Stark theme and request the same page as above. This
// time, we expect hook_custom_theme() to prevail.
theme_enable(array('stark'));
$this->drupalGet('menu-test/theme-callback/use-admin-theme');
$this->assertText('Custom theme: stark. Actual theme: stark.', t('The result of hook_custom_theme() overrides what was set in a theme callback.'));
$this->assertRaw('stark/layout.css', t("The Stark theme's CSS appears on the page."));
}
/**
* Tests for menu_link_maintain().
*/
function testMenuLinkMaintain() {
$admin_user = $this->drupalCreateUser(array('administer site configuration'));
$this->drupalLogin($admin_user);
// Create three menu items.
menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1');
menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1-1');
menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/2', 'Menu link #2');
// Move second link to the main-menu, to test caching later on.
db_update('menu_links')
->fields(array('menu_name' => 'main-menu'))
->condition('link_title', 'Menu link #1-1')
->condition('customized', 0)
->condition('module', 'menu_test')
->execute();
menu_cache_clear('main-menu');
// Load front page.
$this->drupalGet('node');
$this->assertLink(t('Menu link #1'), 0, 'Found menu link #1');
$this->assertLink(t('Menu link #1-1'), 0, 'Found menu link #1-1');
$this->assertLink(t('Menu link #2'), 0, 'Found menu link #2');
// Rename all links for the given path.
menu_link_maintain('menu_test', 'update', 'menu_test_maintain/1', 'Menu link updated');
// Load a different page to be sure that we have up to date information.
$this->drupalGet('menu_test_maintain/1');
$this->assertLink(t('Menu link updated'), 0, t('Found updated menu link'));
$this->assertNoLink(t('Menu link #1'), 0, t('Not found menu link #1'));
$this->assertNoLink(t('Menu link #1'), 0, t('Not found menu link #1-1'));
$this->assertLink(t('Menu link #2'), 0, t('Found menu link #2'));
// Delete all links for the given path.
menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/1', '');
// Load a different page to be sure that we have up to date information.
$this->drupalGet('menu_test_maintain/2');
$this->assertNoLink(t('Menu link updated'), 0, t('Not found deleted menu link'));
$this->assertNoLink(t('Menu link #1'), 0, t('Not found menu link #1'));
$this->assertNoLink(t('Menu link #1'), 0, t('Not found menu link #1-1'));
$this->assertLink(t('Menu link #2'), 0, t('Found menu link #2'));
}
/**
* Test menu_get_names().
*/
function testMenuGetNames() {
// Create three menu items.
for ($i = 0; $i < 3; $i++) {
$menu_link = array(
'link_title' => 'Menu link #' . $i,
'link_path' => 'menu_test/' . $i,
'module' => 'menu_test',
'menu_name' => 'menu_test_' . $i,
);
menu_link_save($menu_link);
}
drupal_static_reset('menu_get_names');
// Verify that the menu names are correctly reported by menu_get_names().
$menu_names = menu_get_names();
$this->pass(implode(' | ', $menu_names));
for ($i = 0; $i < 3; $i++) {
$this->assertTrue(in_array('menu_test_' . $i, $menu_names), t('Expected menu name %expected is returned.', array('%expected' => 'menu_test_' . $i)));
}
}
/**
* Tests for menu_name parameter for hook_menu().
*/
function testMenuName() {
$admin_user = $this->drupalCreateUser(array('administer site configuration'));
$this->drupalLogin($admin_user);
$sql = "SELECT menu_name FROM {menu_links} WHERE router_path = 'menu_name_test'";
$name = db_query($sql)->fetchField();
$this->assertEqual($name, 'original', t('Menu name is "original".'));
// Change the menu_name parameter in menu_test.module, then force a menu
// rebuild.
menu_test_menu_name('changed');
menu_rebuild();
$sql = "SELECT menu_name FROM {menu_links} WHERE router_path = 'menu_name_test'";
$name = db_query($sql)->fetchField();
$this->assertEqual($name, 'changed', t('Menu name was successfully changed after rebuild.'));
}
/**
* Tests for menu hierarchy.
*/
function testMenuHierarchy() {
$parent_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent'))->fetchAssoc();
$child_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent/child'))->fetchAssoc();
$unattached_child_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent/child2/child'))->fetchAssoc();
$this->assertEqual($child_link['plid'], $parent_link['mlid'], t('The parent of a directly attached child is correct.'));
$this->assertEqual($unattached_child_link['plid'], $parent_link['mlid'], t('The parent of a non-directly attached child is correct.'));
}
/**
* Tests menu link depth and parents of local tasks and menu callbacks.
*/
function testMenuHidden() {
// Verify links for one dynamic argument.
$links = db_select('menu_links', 'ml')
->fields('ml')
->condition('ml.router_path', 'menu-test/hidden/menu%', 'LIKE')
->orderBy('ml.router_path')
->execute()
->fetchAllAssoc('router_path', PDO::FETCH_ASSOC);
$parent = $links['menu-test/hidden/menu'];
$depth = $parent['depth'] + 1;
$plid = $parent['mlid'];
$link = $links['menu-test/hidden/menu/list'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
$link = $links['menu-test/hidden/menu/add'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
$link = $links['menu-test/hidden/menu/settings'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
$link = $links['menu-test/hidden/menu/manage/%'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
$parent = $links['menu-test/hidden/menu/manage/%'];
$depth = $parent['depth'] + 1;
$plid = $parent['mlid'];
$link = $links['menu-test/hidden/menu/manage/%/list'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
$link = $links['menu-test/hidden/menu/manage/%/add'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
$link = $links['menu-test/hidden/menu/manage/%/edit'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
$link = $links['menu-test/hidden/menu/manage/%/delete'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
// Verify links for two dynamic arguments.
$links = db_select('menu_links', 'ml')
->fields('ml')
->condition('ml.router_path', 'menu-test/hidden/block%', 'LIKE')
->orderBy('ml.router_path')
->execute()
->fetchAllAssoc('router_path', PDO::FETCH_ASSOC);
$parent = $links['menu-test/hidden/block'];
$depth = $parent['depth'] + 1;
$plid = $parent['mlid'];
$link = $links['menu-test/hidden/block/list'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
$link = $links['menu-test/hidden/block/add'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
$link = $links['menu-test/hidden/block/manage/%/%'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
$parent = $links['menu-test/hidden/block/manage/%/%'];
$depth = $parent['depth'] + 1;
$plid = $parent['mlid'];
$link = $links['menu-test/hidden/block/manage/%/%/configure'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
$link = $links['menu-test/hidden/block/manage/%/%/delete'];
$this->assertEqual($link['depth'], $depth, t('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
$this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
}
/**
* Test menu_set_item().
*/
function testMenuSetItem() {
$item = menu_get_item('node');
$this->assertEqual($item['path'], 'node', t("Path from menu_get_item('node') is equal to 'node'"), 'menu');
// Modify the path for the item then save it.
$item['path'] = 'node_test';
$item['href'] = 'node_test';
menu_set_item('node', $item);
$compare_item = menu_get_item('node');
$this->assertEqual($compare_item, $item, t('Modified menu item is equal to newly retrieved menu item.'), 'menu');
}
/**
* Test menu maintainance hooks.
*/
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', t('hook_menu_link_insert() fired correctly'));
// Update the item.
menu_link_maintain('menu_test', 'update', 'menu_test_maintain/4', 'Menu link updated');
$this->assertEqual(menu_test_static_variable(), 'update', t('hook_menu_link_update() fired correctly'));
// Delete the item.
menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/4', '');
$this->assertEqual(menu_test_static_variable(), 'delete', t('hook_menu_link_delete() fired correctly'));
}
/**
* Test menu link 'options' storage and rendering.
*/
function testMenuLinkOptions() {
// Create a menu link with options.
$menu_link = array(
'link_title' => 'Menu link options test',
'link_path' => 'node',
'module' => 'menu_test',
'options' => array(
'attributes' => array(
'title' => 'Test title attribute',
),
'query' => array(
'testparam' => 'testvalue',
),
),
);
menu_link_save($menu_link);
// Load front page.
$this->drupalGet('node');
$this->assertRaw('title="Test title attribute"', t('Title attribute of a menu link renders.'));
$this->assertRaw('testparam=testvalue', t('Query parameter added to menu link.'));
}
}
/**
* Tests rebuilding the menu by setting 'menu_rebuild_needed.'
*/
class MenuRebuildTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Menu rebuild test',
'description' => 'Test rebuilding of menu.',
'group' => 'Menu',
);
}
/**
* Test if the 'menu_rebuild_needed' variable triggers a menu_rebuild() call.
*/
function testMenuRebuildByVariable() {
// Check if 'admin' path exists.
$admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField();
$this->assertEqual($admin_exists, 'admin', t("The path 'admin/' exists prior to deleting."));
// Delete the path item 'admin', and test that the path doesn't exist in the database.
$delete = db_delete('menu_router')
->condition('path', 'admin')
->execute();
$admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField();
$this->assertFalse($admin_exists, t("The path 'admin/' has been deleted and doesn't exist in the database."));
// Now we enable the rebuild variable and trigger menu_execute_active_handler()
// to rebuild the menu item. Now 'admin' should exist.
variable_set('menu_rebuild_needed', TRUE);
// menu_execute_active_handler() should trigger the rebuild.
$this->drupalGet('<front>');
$admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField();
$this->assertEqual($admin_exists, 'admin', t("The menu has been rebuilt, the path 'admin' now exists again."));
}
}
/**
* Menu tree data related tests.
*/
class MenuTreeDataTestCase extends DrupalUnitTestCase {
/**
* Dummy link structure acceptable for menu_tree_data().
*/
var $links = array(
1 => array('mlid' => 1, 'depth' => 1),
2 => array('mlid' => 2, 'depth' => 1),
3 => array('mlid' => 3, 'depth' => 2),
4 => array('mlid' => 4, 'depth' => 3),
5 => array('mlid' => 5, 'depth' => 1),
);
public static function getInfo() {
return array(
'name' => 'Menu tree generation',
'description' => 'Tests recursive menu tree generation functions.',
'group' => 'Menu',
);
}
/**
* Validate the generation of a proper menu tree hierarchy.
*/
function testMenuTreeData() {
$tree = menu_tree_data($this->links);
// Validate that parent items #1, #2, and #5 exist on the root level.
$this->assertSameLink($this->links[1], $tree[1]['link'], t('Parent item #1 exists.'));
$this->assertSameLink($this->links[2], $tree[2]['link'], t('Parent item #2 exists.'));
$this->assertSameLink($this->links[5], $tree[5]['link'], t('Parent item #5 exists.'));
// Validate that child item #4 exists at the correct location in the hierarchy.
$this->assertSameLink($this->links[4], $tree[2]['below'][3]['below'][4]['link'], t('Child item #4 exists in the hierarchy.'));
}
/**
* Check that two menu links are the same by comparing the mlid.
*
* @param $link1
* A menu link item.
* @param $link2
* A menu link item.
* @param $message
* The message to display along with the assertion.
* @return
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertSameLink($link1, $link2, $message = '') {
return $this->assert($link1['mlid'] == $link2['mlid'], $message ? $message : t('First link is identical to second link'));
}
}