|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Provides SimpleTests for menu.inc. |
|
6 */ |
|
7 |
|
8 class MenuWebTestCase extends DrupalWebTestCase { |
|
9 function setUp() { |
|
10 $modules = func_get_args(); |
|
11 if (isset($modules[0]) && is_array($modules[0])) { |
|
12 $modules = $modules[0]; |
|
13 } |
|
14 parent::setUp($modules); |
|
15 } |
|
16 |
|
17 /** |
|
18 * Assert that a given path shows certain breadcrumb links. |
|
19 * |
|
20 * @param string $goto |
|
21 * (optional) A system path to pass to DrupalWebTestCase::drupalGet(). |
|
22 * @param array $trail |
|
23 * An associative array whose keys are expected breadcrumb link paths and |
|
24 * whose values are expected breadcrumb link texts (not sanitized). |
|
25 * @param string $page_title |
|
26 * (optional) A page title to additionally assert via |
|
27 * DrupalWebTestCase::assertTitle(). Without site name suffix. |
|
28 * @param array $tree |
|
29 * (optional) An associative array whose keys are link paths and whose |
|
30 * values are link titles (not sanitized) of an expected active trail in a |
|
31 * menu tree output on the page. |
|
32 * @param $last_active |
|
33 * (optional) Whether the last link in $tree is expected to be active (TRUE) |
|
34 * or just to be in the active trail (FALSE). |
|
35 */ |
|
36 protected function assertBreadcrumb($goto, array $trail, $page_title = NULL, array $tree = array(), $last_active = TRUE) { |
|
37 if (isset($goto)) { |
|
38 $this->drupalGet($goto); |
|
39 } |
|
40 // Compare paths with actual breadcrumb. |
|
41 $parts = $this->getParts(); |
|
42 $pass = TRUE; |
|
43 foreach ($trail as $path => $title) { |
|
44 $url = url($path); |
|
45 $part = array_shift($parts); |
|
46 $pass = ($pass && $part['href'] === $url && $part['text'] === check_plain($title)); |
|
47 } |
|
48 // No parts must be left, or an expected "Home" will always pass. |
|
49 $pass = ($pass && empty($parts)); |
|
50 |
|
51 $this->assertTrue($pass, format_string('Breadcrumb %parts found on @path.', array( |
|
52 '%parts' => implode(' » ', $trail), |
|
53 '@path' => $this->getUrl(), |
|
54 ))); |
|
55 |
|
56 // Additionally assert page title, if given. |
|
57 if (isset($page_title)) { |
|
58 $this->assertTitle(strtr('@title | Drupal', array('@title' => $page_title))); |
|
59 } |
|
60 |
|
61 // Additionally assert active trail in a menu tree output, if given. |
|
62 if ($tree) { |
|
63 end($tree); |
|
64 $active_link_path = key($tree); |
|
65 $active_link_title = array_pop($tree); |
|
66 $xpath = ''; |
|
67 if ($tree) { |
|
68 $i = 0; |
|
69 foreach ($tree as $link_path => $link_title) { |
|
70 $part_xpath = (!$i ? '//' : '/following-sibling::ul/descendant::'); |
|
71 $part_xpath .= 'li[contains(@class, :class)]/a[contains(@href, :href) and contains(text(), :title)]'; |
|
72 $part_args = array( |
|
73 ':class' => 'active-trail', |
|
74 ':href' => url($link_path), |
|
75 ':title' => $link_title, |
|
76 ); |
|
77 $xpath .= $this->buildXPathQuery($part_xpath, $part_args); |
|
78 $i++; |
|
79 } |
|
80 $elements = $this->xpath($xpath); |
|
81 $this->assertTrue(!empty($elements), 'Active trail to current page was found in menu tree.'); |
|
82 |
|
83 // Append prefix for active link asserted below. |
|
84 $xpath .= '/following-sibling::ul/descendant::'; |
|
85 } |
|
86 else { |
|
87 $xpath .= '//'; |
|
88 } |
|
89 $xpath_last_active = ($last_active ? 'and contains(@class, :class-active)' : ''); |
|
90 $xpath .= 'li[contains(@class, :class-trail)]/a[contains(@href, :href) ' . $xpath_last_active . 'and contains(text(), :title)]'; |
|
91 $args = array( |
|
92 ':class-trail' => 'active-trail', |
|
93 ':class-active' => 'active', |
|
94 ':href' => url($active_link_path), |
|
95 ':title' => $active_link_title, |
|
96 ); |
|
97 $elements = $this->xpath($xpath, $args); |
|
98 $this->assertTrue(!empty($elements), format_string('Active link %title was found in menu tree, including active trail links %tree.', array( |
|
99 '%title' => $active_link_title, |
|
100 '%tree' => implode(' » ', $tree), |
|
101 ))); |
|
102 } |
|
103 } |
|
104 |
|
105 /** |
|
106 * Returns the breadcrumb contents of the current page in the internal browser. |
|
107 */ |
|
108 protected function getParts() { |
|
109 $parts = array(); |
|
110 $elements = $this->xpath('//div[@class="breadcrumb"]/a'); |
|
111 if (!empty($elements)) { |
|
112 foreach ($elements as $element) { |
|
113 $parts[] = array( |
|
114 'text' => (string) $element, |
|
115 'href' => (string) $element['href'], |
|
116 'title' => (string) $element['title'], |
|
117 ); |
|
118 } |
|
119 } |
|
120 return $parts; |
|
121 } |
|
122 } |
|
123 |
|
124 class MenuRouterTestCase extends DrupalWebTestCase { |
|
125 public static function getInfo() { |
|
126 return array( |
|
127 'name' => 'Menu router', |
|
128 'description' => 'Tests menu router and hook_menu() functionality.', |
|
129 'group' => 'Menu', |
|
130 ); |
|
131 } |
|
132 |
|
133 function setUp() { |
|
134 // Enable dummy module that implements hook_menu. |
|
135 parent::setUp('menu_test'); |
|
136 // Make the tests below more robust by explicitly setting the default theme |
|
137 // and administrative theme that they expect. |
|
138 theme_enable(array('bartik')); |
|
139 variable_set('theme_default', 'bartik'); |
|
140 variable_set('admin_theme', 'seven'); |
|
141 } |
|
142 |
|
143 /** |
|
144 * Test title callback set to FALSE. |
|
145 */ |
|
146 function testTitleCallbackFalse() { |
|
147 $this->drupalGet('node'); |
|
148 $this->assertText('A title with @placeholder', 'Raw text found on the page'); |
|
149 $this->assertNoText(t('A title with @placeholder', array('@placeholder' => 'some other text')), 'Text with placeholder substitutions not found.'); |
|
150 } |
|
151 |
|
152 /** |
|
153 * Tests page title of MENU_CALLBACKs. |
|
154 */ |
|
155 function testTitleMenuCallback() { |
|
156 // Verify that the menu router item title is not visible. |
|
157 $this->drupalGet(''); |
|
158 $this->assertNoText(t('Menu Callback Title')); |
|
159 // Verify that the menu router item title is output as page title. |
|
160 $this->drupalGet('menu_callback_title'); |
|
161 $this->assertText(t('Menu Callback Title')); |
|
162 } |
|
163 |
|
164 /** |
|
165 * Test the theme callback when it is set to use an administrative theme. |
|
166 */ |
|
167 function testThemeCallbackAdministrative() { |
|
168 $this->drupalGet('menu-test/theme-callback/use-admin-theme'); |
|
169 $this->assertText('Custom theme: seven. Actual theme: seven.', 'The administrative theme can be correctly set in a theme callback.'); |
|
170 $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page."); |
|
171 } |
|
172 |
|
173 /** |
|
174 * Test that the theme callback is properly inherited. |
|
175 */ |
|
176 function testThemeCallbackInheritance() { |
|
177 $this->drupalGet('menu-test/theme-callback/use-admin-theme/inheritance'); |
|
178 $this->assertText('Custom theme: seven. Actual theme: seven. Theme callback inheritance is being tested.', 'Theme callback inheritance correctly uses the administrative theme.'); |
|
179 $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page."); |
|
180 } |
|
181 |
|
182 /** |
|
183 * Test that 'page callback', 'file' and 'file path' keys are properly |
|
184 * inherited from parent menu paths. |
|
185 */ |
|
186 function testFileInheritance() { |
|
187 $this->drupalGet('admin/config/development/file-inheritance'); |
|
188 $this->assertText('File inheritance test description', 'File inheritance works.'); |
|
189 } |
|
190 |
|
191 /** |
|
192 * Test path containing "exotic" characters. |
|
193 */ |
|
194 function testExoticPath() { |
|
195 $path = "menu-test/ -._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters. |
|
196 "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string. |
|
197 "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets. |
|
198 $this->drupalGet($path); |
|
199 $this->assertRaw('This is menu_test_callback().'); |
|
200 } |
|
201 |
|
202 /** |
|
203 * Test the theme callback when the site is in maintenance mode. |
|
204 */ |
|
205 function testThemeCallbackMaintenanceMode() { |
|
206 variable_set('maintenance_mode', TRUE); |
|
207 |
|
208 // For a regular user, the fact that the site is in maintenance mode means |
|
209 // we expect the theme callback system to be bypassed entirely. |
|
210 $this->drupalGet('menu-test/theme-callback/use-admin-theme'); |
|
211 $this->assertRaw('bartik/css/style.css', "The maintenance theme's CSS appears on the page."); |
|
212 |
|
213 // An administrator, however, should continue to see the requested theme. |
|
214 $admin_user = $this->drupalCreateUser(array('access site in maintenance mode')); |
|
215 $this->drupalLogin($admin_user); |
|
216 $this->drupalGet('menu-test/theme-callback/use-admin-theme'); |
|
217 $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.'); |
|
218 $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page."); |
|
219 } |
|
220 |
|
221 /** |
|
222 * Make sure the maintenance mode can be bypassed using hook_menu_site_status_alter(). |
|
223 * |
|
224 * @see hook_menu_site_status_alter(). |
|
225 */ |
|
226 function testMaintenanceModeLoginPaths() { |
|
227 variable_set('maintenance_mode', TRUE); |
|
228 |
|
229 $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal'))); |
|
230 $this->drupalLogout(); |
|
231 $this->drupalGet('node'); |
|
232 $this->assertText($offline_message); |
|
233 $this->drupalGet('menu_login_callback'); |
|
234 $this->assertText('This is menu_login_callback().', t('Maintenance mode can be bypassed through hook_login_paths().')); |
|
235 } |
|
236 |
|
237 /** |
|
238 * Test that an authenticated user hitting 'user/login' gets redirected to |
|
239 * 'user' and 'user/register' gets redirected to the user edit page. |
|
240 */ |
|
241 function testAuthUserUserLogin() { |
|
242 $loggedInUser = $this->drupalCreateUser(array()); |
|
243 $this->drupalLogin($loggedInUser); |
|
244 |
|
245 $this->drupalGet('user/login'); |
|
246 // Check that we got to 'user'. |
|
247 $this->assertTrue($this->url == url('user', array('absolute' => TRUE)), "Logged-in user redirected to q=user on accessing q=user/login"); |
|
248 |
|
249 // user/register should redirect to user/UID/edit. |
|
250 $this->drupalGet('user/register'); |
|
251 $this->assertTrue($this->url == url('user/' . $this->loggedInUser->uid . '/edit', array('absolute' => TRUE)), "Logged-in user redirected to q=user/UID/edit on accessing q=user/register"); |
|
252 } |
|
253 |
|
254 /** |
|
255 * Test the theme callback when it is set to use an optional theme. |
|
256 */ |
|
257 function testThemeCallbackOptionalTheme() { |
|
258 // Request a theme that is not enabled. |
|
259 $this->drupalGet('menu-test/theme-callback/use-stark-theme'); |
|
260 $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.'); |
|
261 $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page."); |
|
262 |
|
263 // Now enable the theme and request it again. |
|
264 theme_enable(array('stark')); |
|
265 $this->drupalGet('menu-test/theme-callback/use-stark-theme'); |
|
266 $this->assertText('Custom theme: stark. Actual theme: stark.', 'The theme callback system uses an optional theme once it has been enabled.'); |
|
267 $this->assertRaw('stark/layout.css', "The optional theme's CSS appears on the page."); |
|
268 } |
|
269 |
|
270 /** |
|
271 * Test the theme callback when it is set to use a theme that does not exist. |
|
272 */ |
|
273 function testThemeCallbackFakeTheme() { |
|
274 $this->drupalGet('menu-test/theme-callback/use-fake-theme'); |
|
275 $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.'); |
|
276 $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page."); |
|
277 } |
|
278 |
|
279 /** |
|
280 * Test the theme callback when no theme is requested. |
|
281 */ |
|
282 function testThemeCallbackNoThemeRequested() { |
|
283 $this->drupalGet('menu-test/theme-callback/no-theme-requested'); |
|
284 $this->assertText('Custom theme: NONE. Actual theme: bartik.', 'The theme callback system falls back on the default theme when no theme is requested.'); |
|
285 $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page."); |
|
286 } |
|
287 |
|
288 /** |
|
289 * Test that hook_custom_theme() can control the theme of a page. |
|
290 */ |
|
291 function testHookCustomTheme() { |
|
292 // Trigger hook_custom_theme() to dynamically request the Stark theme for |
|
293 // the requested page. |
|
294 variable_set('menu_test_hook_custom_theme_name', 'stark'); |
|
295 theme_enable(array('stark')); |
|
296 |
|
297 // Visit a page that does not implement a theme callback. The above request |
|
298 // should be honored. |
|
299 $this->drupalGet('menu-test/no-theme-callback'); |
|
300 $this->assertText('Custom theme: stark. Actual theme: stark.', 'The result of hook_custom_theme() is used as the theme for the current page.'); |
|
301 $this->assertRaw('stark/layout.css', "The Stark theme's CSS appears on the page."); |
|
302 } |
|
303 |
|
304 /** |
|
305 * Test that the theme callback wins out over hook_custom_theme(). |
|
306 */ |
|
307 function testThemeCallbackHookCustomTheme() { |
|
308 // Trigger hook_custom_theme() to dynamically request the Stark theme for |
|
309 // the requested page. |
|
310 variable_set('menu_test_hook_custom_theme_name', 'stark'); |
|
311 theme_enable(array('stark')); |
|
312 |
|
313 // The menu "theme callback" should take precedence over a value set in |
|
314 // hook_custom_theme(). |
|
315 $this->drupalGet('menu-test/theme-callback/use-admin-theme'); |
|
316 $this->assertText('Custom theme: seven. Actual theme: seven.', 'The result of hook_custom_theme() does not override what was set in a theme callback.'); |
|
317 $this->assertRaw('seven/style.css', "The Seven theme's CSS appears on the page."); |
|
318 } |
|
319 |
|
320 /** |
|
321 * Tests for menu_link_maintain(). |
|
322 */ |
|
323 function testMenuLinkMaintain() { |
|
324 $admin_user = $this->drupalCreateUser(array('administer site configuration')); |
|
325 $this->drupalLogin($admin_user); |
|
326 |
|
327 // Create three menu items. |
|
328 menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1'); |
|
329 menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1-1'); |
|
330 menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/2', 'Menu link #2'); |
|
331 |
|
332 // Move second link to the main-menu, to test caching later on. |
|
333 db_update('menu_links') |
|
334 ->fields(array('menu_name' => 'main-menu')) |
|
335 ->condition('link_title', 'Menu link #1-1') |
|
336 ->condition('customized', 0) |
|
337 ->condition('module', 'menu_test') |
|
338 ->execute(); |
|
339 menu_cache_clear('main-menu'); |
|
340 |
|
341 // Load front page. |
|
342 $this->drupalGet('node'); |
|
343 $this->assertLink(t('Menu link #1'), 0, 'Found menu link #1'); |
|
344 $this->assertLink(t('Menu link #1-1'), 0, 'Found menu link #1-1'); |
|
345 $this->assertLink(t('Menu link #2'), 0, 'Found menu link #2'); |
|
346 |
|
347 // Rename all links for the given path. |
|
348 menu_link_maintain('menu_test', 'update', 'menu_test_maintain/1', 'Menu link updated'); |
|
349 // Load a different page to be sure that we have up to date information. |
|
350 $this->drupalGet('menu_test_maintain/1'); |
|
351 $this->assertLink(t('Menu link updated'), 0, 'Found updated menu link'); |
|
352 $this->assertNoLink(t('Menu link #1'), 0, 'Not found menu link #1'); |
|
353 $this->assertNoLink(t('Menu link #1'), 0, 'Not found menu link #1-1'); |
|
354 $this->assertLink(t('Menu link #2'), 0, 'Found menu link #2'); |
|
355 |
|
356 // Delete all links for the given path. |
|
357 menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/1', ''); |
|
358 // Load a different page to be sure that we have up to date information. |
|
359 $this->drupalGet('menu_test_maintain/2'); |
|
360 $this->assertNoLink(t('Menu link updated'), 0, 'Not found deleted menu link'); |
|
361 $this->assertNoLink(t('Menu link #1'), 0, 'Not found menu link #1'); |
|
362 $this->assertNoLink(t('Menu link #1'), 0, 'Not found menu link #1-1'); |
|
363 $this->assertLink(t('Menu link #2'), 0, 'Found menu link #2'); |
|
364 } |
|
365 |
|
366 /** |
|
367 * Test menu_get_names(). |
|
368 */ |
|
369 function testMenuGetNames() { |
|
370 // Create three menu items. |
|
371 for ($i = 0; $i < 3; $i++) { |
|
372 $menu_link = array( |
|
373 'link_title' => 'Menu link #' . $i, |
|
374 'link_path' => 'menu_test/' . $i, |
|
375 'module' => 'menu_test', |
|
376 'menu_name' => 'menu_test_' . $i, |
|
377 ); |
|
378 menu_link_save($menu_link); |
|
379 } |
|
380 |
|
381 drupal_static_reset('menu_get_names'); |
|
382 |
|
383 // Verify that the menu names are correctly reported by menu_get_names(). |
|
384 $menu_names = menu_get_names(); |
|
385 $this->pass(implode(' | ', $menu_names)); |
|
386 for ($i = 0; $i < 3; $i++) { |
|
387 $this->assertTrue(in_array('menu_test_' . $i, $menu_names), t('Expected menu name %expected is returned.', array('%expected' => 'menu_test_' . $i))); |
|
388 } |
|
389 } |
|
390 |
|
391 /** |
|
392 * Tests for menu_name parameter for hook_menu(). |
|
393 */ |
|
394 function testMenuName() { |
|
395 $admin_user = $this->drupalCreateUser(array('administer site configuration')); |
|
396 $this->drupalLogin($admin_user); |
|
397 |
|
398 $sql = "SELECT menu_name FROM {menu_links} WHERE router_path = 'menu_name_test'"; |
|
399 $name = db_query($sql)->fetchField(); |
|
400 $this->assertEqual($name, 'original', 'Menu name is "original".'); |
|
401 |
|
402 // Change the menu_name parameter in menu_test.module, then force a menu |
|
403 // rebuild. |
|
404 menu_test_menu_name('changed'); |
|
405 menu_rebuild(); |
|
406 |
|
407 $sql = "SELECT menu_name FROM {menu_links} WHERE router_path = 'menu_name_test'"; |
|
408 $name = db_query($sql)->fetchField(); |
|
409 $this->assertEqual($name, 'changed', 'Menu name was successfully changed after rebuild.'); |
|
410 } |
|
411 |
|
412 /** |
|
413 * Tests for menu hierarchy. |
|
414 */ |
|
415 function testMenuHierarchy() { |
|
416 $parent_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent'))->fetchAssoc(); |
|
417 $child_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent/child'))->fetchAssoc(); |
|
418 $unattached_child_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent/child2/child'))->fetchAssoc(); |
|
419 |
|
420 $this->assertEqual($child_link['plid'], $parent_link['mlid'], 'The parent of a directly attached child is correct.'); |
|
421 $this->assertEqual($unattached_child_link['plid'], $parent_link['mlid'], 'The parent of a non-directly attached child is correct.'); |
|
422 } |
|
423 |
|
424 /** |
|
425 * Tests menu link depth and parents of local tasks and menu callbacks. |
|
426 */ |
|
427 function testMenuHidden() { |
|
428 // Verify links for one dynamic argument. |
|
429 $links = db_select('menu_links', 'ml') |
|
430 ->fields('ml') |
|
431 ->condition('ml.router_path', 'menu-test/hidden/menu%', 'LIKE') |
|
432 ->orderBy('ml.router_path') |
|
433 ->execute() |
|
434 ->fetchAllAssoc('router_path', PDO::FETCH_ASSOC); |
|
435 |
|
436 $parent = $links['menu-test/hidden/menu']; |
|
437 $depth = $parent['depth'] + 1; |
|
438 $plid = $parent['mlid']; |
|
439 |
|
440 $link = $links['menu-test/hidden/menu/list']; |
|
441 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
442 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
443 |
|
444 $link = $links['menu-test/hidden/menu/add']; |
|
445 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
446 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
447 |
|
448 $link = $links['menu-test/hidden/menu/settings']; |
|
449 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
450 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
451 |
|
452 $link = $links['menu-test/hidden/menu/manage/%']; |
|
453 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
454 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
455 |
|
456 $parent = $links['menu-test/hidden/menu/manage/%']; |
|
457 $depth = $parent['depth'] + 1; |
|
458 $plid = $parent['mlid']; |
|
459 |
|
460 $link = $links['menu-test/hidden/menu/manage/%/list']; |
|
461 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
462 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
463 |
|
464 $link = $links['menu-test/hidden/menu/manage/%/add']; |
|
465 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
466 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
467 |
|
468 $link = $links['menu-test/hidden/menu/manage/%/edit']; |
|
469 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
470 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
471 |
|
472 $link = $links['menu-test/hidden/menu/manage/%/delete']; |
|
473 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
474 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
475 |
|
476 // Verify links for two dynamic arguments. |
|
477 $links = db_select('menu_links', 'ml') |
|
478 ->fields('ml') |
|
479 ->condition('ml.router_path', 'menu-test/hidden/block%', 'LIKE') |
|
480 ->orderBy('ml.router_path') |
|
481 ->execute() |
|
482 ->fetchAllAssoc('router_path', PDO::FETCH_ASSOC); |
|
483 |
|
484 $parent = $links['menu-test/hidden/block']; |
|
485 $depth = $parent['depth'] + 1; |
|
486 $plid = $parent['mlid']; |
|
487 |
|
488 $link = $links['menu-test/hidden/block/list']; |
|
489 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
490 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
491 |
|
492 $link = $links['menu-test/hidden/block/add']; |
|
493 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
494 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
495 |
|
496 $link = $links['menu-test/hidden/block/manage/%/%']; |
|
497 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
498 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
499 |
|
500 $parent = $links['menu-test/hidden/block/manage/%/%']; |
|
501 $depth = $parent['depth'] + 1; |
|
502 $plid = $parent['mlid']; |
|
503 |
|
504 $link = $links['menu-test/hidden/block/manage/%/%/configure']; |
|
505 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
506 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
507 |
|
508 $link = $links['menu-test/hidden/block/manage/%/%/delete']; |
|
509 $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth))); |
|
510 $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); |
|
511 } |
|
512 |
|
513 /** |
|
514 * Test menu_get_item() with empty ancestors. |
|
515 */ |
|
516 function testMenuGetItemNoAncestors() { |
|
517 variable_set('menu_masks', array()); |
|
518 $this->drupalGet(''); |
|
519 } |
|
520 |
|
521 /** |
|
522 * Test menu_set_item(). |
|
523 */ |
|
524 function testMenuSetItem() { |
|
525 $item = menu_get_item('node'); |
|
526 |
|
527 $this->assertEqual($item['path'], 'node', "Path from menu_get_item('node') is equal to 'node'", 'menu'); |
|
528 |
|
529 // Modify the path for the item then save it. |
|
530 $item['path'] = 'node_test'; |
|
531 $item['href'] = 'node_test'; |
|
532 |
|
533 menu_set_item('node', $item); |
|
534 $compare_item = menu_get_item('node'); |
|
535 $this->assertEqual($compare_item, $item, 'Modified menu item is equal to newly retrieved menu item.', 'menu'); |
|
536 } |
|
537 |
|
538 /** |
|
539 * Test menu maintenance hooks. |
|
540 */ |
|
541 function testMenuItemHooks() { |
|
542 // Create an item. |
|
543 menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/4', 'Menu link #4'); |
|
544 $this->assertEqual(menu_test_static_variable(), 'insert', 'hook_menu_link_insert() fired correctly'); |
|
545 // Update the item. |
|
546 menu_link_maintain('menu_test', 'update', 'menu_test_maintain/4', 'Menu link updated'); |
|
547 $this->assertEqual(menu_test_static_variable(), 'update', 'hook_menu_link_update() fired correctly'); |
|
548 // Delete the item. |
|
549 menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/4', ''); |
|
550 $this->assertEqual(menu_test_static_variable(), 'delete', 'hook_menu_link_delete() fired correctly'); |
|
551 } |
|
552 |
|
553 /** |
|
554 * Test menu link 'options' storage and rendering. |
|
555 */ |
|
556 function testMenuLinkOptions() { |
|
557 // Create a menu link with options. |
|
558 $menu_link = array( |
|
559 'link_title' => 'Menu link options test', |
|
560 'link_path' => 'node', |
|
561 'module' => 'menu_test', |
|
562 'options' => array( |
|
563 'attributes' => array( |
|
564 'title' => 'Test title attribute', |
|
565 ), |
|
566 'query' => array( |
|
567 'testparam' => 'testvalue', |
|
568 ), |
|
569 ), |
|
570 ); |
|
571 menu_link_save($menu_link); |
|
572 |
|
573 // Load front page. |
|
574 $this->drupalGet('node'); |
|
575 $this->assertRaw('title="Test title attribute"', 'Title attribute of a menu link renders.'); |
|
576 $this->assertRaw('testparam=testvalue', 'Query parameter added to menu link.'); |
|
577 } |
|
578 |
|
579 /** |
|
580 * Tests the possible ways to set the title for menu items. |
|
581 * Also tests that menu item titles work with string overrides. |
|
582 */ |
|
583 function testMenuItemTitlesCases() { |
|
584 |
|
585 // Build array with string overrides. |
|
586 $test_data = array( |
|
587 1 => array('Example title - Case 1' => 'Alternative example title - Case 1'), |
|
588 2 => array('Example @sub1 - Case @op2' => 'Alternative example @sub1 - Case @op2'), |
|
589 3 => array('Example title' => 'Alternative example title'), |
|
590 4 => array('Example title' => 'Alternative example title'), |
|
591 ); |
|
592 |
|
593 foreach ($test_data as $case_no => $override) { |
|
594 $this->menuItemTitlesCasesHelper($case_no); |
|
595 variable_set('locale_custom_strings_en', array('' => $override)); |
|
596 $this->menuItemTitlesCasesHelper($case_no, TRUE); |
|
597 variable_set('locale_custom_strings_en', array()); |
|
598 } |
|
599 } |
|
600 |
|
601 /** |
|
602 * Get a URL and assert the title given a case number. If override is true, |
|
603 * the title is asserted to begin with "Alternative". |
|
604 */ |
|
605 private function menuItemTitlesCasesHelper($case_no, $override = FALSE) { |
|
606 $this->drupalGet('menu-title-test/case' . $case_no); |
|
607 $this->assertResponse(200); |
|
608 $asserted_title = $override ? 'Alternative example title - Case ' . $case_no : 'Example title - Case ' . $case_no; |
|
609 $this->assertTitle($asserted_title . ' | Drupal', format_string('Menu title is: %title.', array('%title' => $asserted_title)), 'Menu'); |
|
610 } |
|
611 |
|
612 /** |
|
613 * Load the router for a given path. |
|
614 */ |
|
615 protected function menuLoadRouter($router_path) { |
|
616 return db_query('SELECT * FROM {menu_router} WHERE path = :path', array(':path' => $router_path))->fetchAssoc(); |
|
617 } |
|
618 |
|
619 /** |
|
620 * Tests inheritance of 'load arguments'. |
|
621 */ |
|
622 function testMenuLoadArgumentsInheritance() { |
|
623 $expected = array( |
|
624 'menu-test/arguments/%/%' => array( |
|
625 2 => array('menu_test_argument_load' => array(3)), |
|
626 3 => NULL, |
|
627 ), |
|
628 // Arguments are inherited to normal children. |
|
629 'menu-test/arguments/%/%/default' => array( |
|
630 2 => array('menu_test_argument_load' => array(3)), |
|
631 3 => NULL, |
|
632 ), |
|
633 // Arguments are inherited to tab children. |
|
634 'menu-test/arguments/%/%/task' => array( |
|
635 2 => array('menu_test_argument_load' => array(3)), |
|
636 3 => NULL, |
|
637 ), |
|
638 // Arguments are only inherited to the same loader functions. |
|
639 'menu-test/arguments/%/%/common-loader' => array( |
|
640 2 => array('menu_test_argument_load' => array(3)), |
|
641 3 => 'menu_test_other_argument_load', |
|
642 ), |
|
643 // Arguments are not inherited to children not using the same loader |
|
644 // function. |
|
645 'menu-test/arguments/%/%/different-loaders-1' => array( |
|
646 2 => NULL, |
|
647 3 => 'menu_test_argument_load', |
|
648 ), |
|
649 'menu-test/arguments/%/%/different-loaders-2' => array( |
|
650 2 => 'menu_test_other_argument_load', |
|
651 3 => NULL, |
|
652 ), |
|
653 'menu-test/arguments/%/%/different-loaders-3' => array( |
|
654 2 => NULL, |
|
655 3 => NULL, |
|
656 ), |
|
657 // Explicit loader arguments should not be overriden by parent. |
|
658 'menu-test/arguments/%/%/explicit-arguments' => array( |
|
659 2 => array('menu_test_argument_load' => array()), |
|
660 3 => NULL, |
|
661 ), |
|
662 ); |
|
663 |
|
664 foreach ($expected as $router_path => $load_functions) { |
|
665 $router_item = $this->menuLoadRouter($router_path); |
|
666 $this->assertIdentical(unserialize($router_item['load_functions']), $load_functions, format_string('Expected load functions for router %router_path' , array('%router_path' => $router_path))); |
|
667 } |
|
668 } |
|
669 } |
|
670 |
|
671 /** |
|
672 * Tests for menu links. |
|
673 */ |
|
674 class MenuLinksUnitTestCase extends DrupalWebTestCase { |
|
675 // Use the lightweight testing profile for this test. |
|
676 protected $profile = 'testing'; |
|
677 |
|
678 public static function getInfo() { |
|
679 return array( |
|
680 'name' => 'Menu links', |
|
681 'description' => 'Test handling of menu links hierarchies.', |
|
682 'group' => 'Menu', |
|
683 ); |
|
684 } |
|
685 |
|
686 /** |
|
687 * Create a simple hierarchy of links. |
|
688 */ |
|
689 function createLinkHierarchy($module = 'menu_test') { |
|
690 // First remove all the menu links. |
|
691 db_truncate('menu_links')->execute(); |
|
692 |
|
693 // Then create a simple link hierarchy: |
|
694 // - $parent |
|
695 // - $child-1 |
|
696 // - $child-1-1 |
|
697 // - $child-1-2 |
|
698 // - $child-2 |
|
699 $base_options = array( |
|
700 'link_title' => 'Menu link test', |
|
701 'module' => $module, |
|
702 'menu_name' => 'menu_test', |
|
703 ); |
|
704 |
|
705 $links['parent'] = $base_options + array( |
|
706 'link_path' => 'menu-test/parent', |
|
707 ); |
|
708 menu_link_save($links['parent']); |
|
709 |
|
710 $links['child-1'] = $base_options + array( |
|
711 'link_path' => 'menu-test/parent/child-1', |
|
712 'plid' => $links['parent']['mlid'], |
|
713 ); |
|
714 menu_link_save($links['child-1']); |
|
715 |
|
716 $links['child-1-1'] = $base_options + array( |
|
717 'link_path' => 'menu-test/parent/child-1/child-1-1', |
|
718 'plid' => $links['child-1']['mlid'], |
|
719 ); |
|
720 menu_link_save($links['child-1-1']); |
|
721 |
|
722 $links['child-1-2'] = $base_options + array( |
|
723 'link_path' => 'menu-test/parent/child-1/child-1-2', |
|
724 'plid' => $links['child-1']['mlid'], |
|
725 ); |
|
726 menu_link_save($links['child-1-2']); |
|
727 |
|
728 $links['child-2'] = $base_options + array( |
|
729 'link_path' => 'menu-test/parent/child-2', |
|
730 'plid' => $links['parent']['mlid'], |
|
731 ); |
|
732 menu_link_save($links['child-2']); |
|
733 |
|
734 return $links; |
|
735 } |
|
736 |
|
737 /** |
|
738 * Assert that at set of links is properly parented. |
|
739 */ |
|
740 function assertMenuLinkParents($links, $expected_hierarchy) { |
|
741 foreach ($expected_hierarchy as $child => $parent) { |
|
742 $mlid = $links[$child]['mlid']; |
|
743 $plid = $parent ? $links[$parent]['mlid'] : 0; |
|
744 |
|
745 $menu_link = menu_link_load($mlid); |
|
746 menu_link_save($menu_link); |
|
747 $this->assertEqual($menu_link['plid'], $plid, format_string('Menu link %mlid has parent of %plid, expected %expected_plid.', array('%mlid' => $mlid, '%plid' => $menu_link['plid'], '%expected_plid' => $plid))); |
|
748 } |
|
749 } |
|
750 |
|
751 /** |
|
752 * Test automatic reparenting of menu links. |
|
753 */ |
|
754 function testMenuLinkReparenting($module = 'menu_test') { |
|
755 // Check the initial hierarchy. |
|
756 $links = $this->createLinkHierarchy($module); |
|
757 |
|
758 $expected_hierarchy = array( |
|
759 'parent' => FALSE, |
|
760 'child-1' => 'parent', |
|
761 'child-1-1' => 'child-1', |
|
762 'child-1-2' => 'child-1', |
|
763 'child-2' => 'parent', |
|
764 ); |
|
765 $this->assertMenuLinkParents($links, $expected_hierarchy); |
|
766 |
|
767 // Start over, and move child-1 under child-2, and check that all the |
|
768 // childs of child-1 have been moved too. |
|
769 $links = $this->createLinkHierarchy($module); |
|
770 $links['child-1']['plid'] = $links['child-2']['mlid']; |
|
771 menu_link_save($links['child-1']); |
|
772 |
|
773 $expected_hierarchy = array( |
|
774 'parent' => FALSE, |
|
775 'child-1' => 'child-2', |
|
776 'child-1-1' => 'child-1', |
|
777 'child-1-2' => 'child-1', |
|
778 'child-2' => 'parent', |
|
779 ); |
|
780 $this->assertMenuLinkParents($links, $expected_hierarchy); |
|
781 |
|
782 // Start over, and delete child-1, and check that the children of child-1 |
|
783 // have been reassigned to the parent. menu_link_delete() will cowardly |
|
784 // refuse to delete a menu link defined by the system module, so skip the |
|
785 // test in that case. |
|
786 if ($module != 'system') { |
|
787 $links = $this->createLinkHierarchy($module); |
|
788 menu_link_delete($links['child-1']['mlid']); |
|
789 |
|
790 $expected_hierarchy = array( |
|
791 'parent' => FALSE, |
|
792 'child-1-1' => 'parent', |
|
793 'child-1-2' => 'parent', |
|
794 'child-2' => 'parent', |
|
795 ); |
|
796 $this->assertMenuLinkParents($links, $expected_hierarchy); |
|
797 } |
|
798 |
|
799 // Start over, forcefully delete child-1 from the database, simulating a |
|
800 // database crash. Check that the children of child-1 have been reassigned |
|
801 // to the parent, going up on the old path hierarchy stored in each of the |
|
802 // links. |
|
803 $links = $this->createLinkHierarchy($module); |
|
804 // Don't do that at home. |
|
805 db_delete('menu_links') |
|
806 ->condition('mlid', $links['child-1']['mlid']) |
|
807 ->execute(); |
|
808 |
|
809 $expected_hierarchy = array( |
|
810 'parent' => FALSE, |
|
811 'child-1-1' => 'parent', |
|
812 'child-1-2' => 'parent', |
|
813 'child-2' => 'parent', |
|
814 ); |
|
815 $this->assertMenuLinkParents($links, $expected_hierarchy); |
|
816 |
|
817 // Start over, forcefully delete the parent from the database, simulating a |
|
818 // database crash. Check that the children of parent are now top-level. |
|
819 $links = $this->createLinkHierarchy($module); |
|
820 // Don't do that at home. |
|
821 db_delete('menu_links') |
|
822 ->condition('mlid', $links['parent']['mlid']) |
|
823 ->execute(); |
|
824 |
|
825 $expected_hierarchy = array( |
|
826 'child-1-1' => 'child-1', |
|
827 'child-1-2' => 'child-1', |
|
828 'child-2' => FALSE, |
|
829 ); |
|
830 $this->assertMenuLinkParents($links, $expected_hierarchy); |
|
831 } |
|
832 |
|
833 /** |
|
834 * Test automatic reparenting of menu links derived from menu routers. |
|
835 */ |
|
836 function testMenuLinkRouterReparenting() { |
|
837 // Run all the standard parenting tests on menu links derived from |
|
838 // menu routers. |
|
839 $this->testMenuLinkReparenting('system'); |
|
840 |
|
841 // Additionnaly, test reparenting based on path. |
|
842 $links = $this->createLinkHierarchy('system'); |
|
843 |
|
844 // Move child-1-2 has a child of child-2, making the link hierarchy |
|
845 // inconsistent with the path hierarchy. |
|
846 $links['child-1-2']['plid'] = $links['child-2']['mlid']; |
|
847 menu_link_save($links['child-1-2']); |
|
848 |
|
849 // Check the new hierarchy. |
|
850 $expected_hierarchy = array( |
|
851 'parent' => FALSE, |
|
852 'child-1' => 'parent', |
|
853 'child-1-1' => 'child-1', |
|
854 'child-2' => 'parent', |
|
855 'child-1-2' => 'child-2', |
|
856 ); |
|
857 $this->assertMenuLinkParents($links, $expected_hierarchy); |
|
858 |
|
859 // Now delete 'parent' directly from the database, simulating a database |
|
860 // crash. 'child-1' and 'child-2' should get moved to the |
|
861 // top-level. |
|
862 // Don't do that at home. |
|
863 db_delete('menu_links') |
|
864 ->condition('mlid', $links['parent']['mlid']) |
|
865 ->execute(); |
|
866 $expected_hierarchy = array( |
|
867 'child-1' => FALSE, |
|
868 'child-1-1' => 'child-1', |
|
869 'child-2' => FALSE, |
|
870 'child-1-2' => 'child-2', |
|
871 ); |
|
872 $this->assertMenuLinkParents($links, $expected_hierarchy); |
|
873 |
|
874 // Now delete 'child-2' directly from the database, simulating a database |
|
875 // crash. 'child-1-2' will get reparented under 'child-1' based on its |
|
876 // path. |
|
877 // Don't do that at home. |
|
878 db_delete('menu_links') |
|
879 ->condition('mlid', $links['child-2']['mlid']) |
|
880 ->execute(); |
|
881 $expected_hierarchy = array( |
|
882 'child-1' => FALSE, |
|
883 'child-1-1' => 'child-1', |
|
884 'child-1-2' => 'child-1', |
|
885 ); |
|
886 $this->assertMenuLinkParents($links, $expected_hierarchy); |
|
887 } |
|
888 } |
|
889 |
|
890 /** |
|
891 * Tests rebuilding the menu by setting 'menu_rebuild_needed.' |
|
892 */ |
|
893 class MenuRebuildTestCase extends DrupalWebTestCase { |
|
894 public static function getInfo() { |
|
895 return array( |
|
896 'name' => 'Menu rebuild test', |
|
897 'description' => 'Test rebuilding of menu.', |
|
898 'group' => 'Menu', |
|
899 ); |
|
900 } |
|
901 |
|
902 /** |
|
903 * Test if the 'menu_rebuild_needed' variable triggers a menu_rebuild() call. |
|
904 */ |
|
905 function testMenuRebuildByVariable() { |
|
906 // Check if 'admin' path exists. |
|
907 $admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField(); |
|
908 $this->assertEqual($admin_exists, 'admin', "The path 'admin/' exists prior to deleting."); |
|
909 |
|
910 // Delete the path item 'admin', and test that the path doesn't exist in the database. |
|
911 $delete = db_delete('menu_router') |
|
912 ->condition('path', 'admin') |
|
913 ->execute(); |
|
914 $admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField(); |
|
915 $this->assertFalse($admin_exists, "The path 'admin/' has been deleted and doesn't exist in the database."); |
|
916 |
|
917 // Now we enable the rebuild variable and trigger menu_execute_active_handler() |
|
918 // to rebuild the menu item. Now 'admin' should exist. |
|
919 variable_set('menu_rebuild_needed', TRUE); |
|
920 // menu_execute_active_handler() should trigger the rebuild. |
|
921 $this->drupalGet('<front>'); |
|
922 $admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField(); |
|
923 $this->assertEqual($admin_exists, 'admin', "The menu has been rebuilt, the path 'admin' now exists again."); |
|
924 } |
|
925 |
|
926 } |
|
927 |
|
928 /** |
|
929 * Menu tree data related tests. |
|
930 */ |
|
931 class MenuTreeDataTestCase extends DrupalUnitTestCase { |
|
932 /** |
|
933 * Dummy link structure acceptable for menu_tree_data(). |
|
934 */ |
|
935 var $links = array( |
|
936 1 => array('mlid' => 1, 'depth' => 1), |
|
937 2 => array('mlid' => 2, 'depth' => 1), |
|
938 3 => array('mlid' => 3, 'depth' => 2), |
|
939 4 => array('mlid' => 4, 'depth' => 3), |
|
940 5 => array('mlid' => 5, 'depth' => 1), |
|
941 ); |
|
942 |
|
943 public static function getInfo() { |
|
944 return array( |
|
945 'name' => 'Menu tree generation', |
|
946 'description' => 'Tests recursive menu tree generation functions.', |
|
947 'group' => 'Menu', |
|
948 ); |
|
949 } |
|
950 |
|
951 /** |
|
952 * Validate the generation of a proper menu tree hierarchy. |
|
953 */ |
|
954 function testMenuTreeData() { |
|
955 $tree = menu_tree_data($this->links); |
|
956 |
|
957 // Validate that parent items #1, #2, and #5 exist on the root level. |
|
958 $this->assertSameLink($this->links[1], $tree[1]['link'], 'Parent item #1 exists.'); |
|
959 $this->assertSameLink($this->links[2], $tree[2]['link'], 'Parent item #2 exists.'); |
|
960 $this->assertSameLink($this->links[5], $tree[5]['link'], 'Parent item #5 exists.'); |
|
961 |
|
962 // Validate that child item #4 exists at the correct location in the hierarchy. |
|
963 $this->assertSameLink($this->links[4], $tree[2]['below'][3]['below'][4]['link'], 'Child item #4 exists in the hierarchy.'); |
|
964 } |
|
965 |
|
966 /** |
|
967 * Check that two menu links are the same by comparing the mlid. |
|
968 * |
|
969 * @param $link1 |
|
970 * A menu link item. |
|
971 * @param $link2 |
|
972 * A menu link item. |
|
973 * @param $message |
|
974 * The message to display along with the assertion. |
|
975 * @return |
|
976 * TRUE if the assertion succeeded, FALSE otherwise. |
|
977 */ |
|
978 protected function assertSameLink($link1, $link2, $message = '') { |
|
979 return $this->assert($link1['mlid'] == $link2['mlid'], $message ? $message : 'First link is identical to second link'); |
|
980 } |
|
981 } |
|
982 |
|
983 /** |
|
984 * Menu tree output related tests. |
|
985 */ |
|
986 class MenuTreeOutputTestCase extends DrupalWebTestCase { |
|
987 /** |
|
988 * Dummy link structure acceptable for menu_tree_output(). |
|
989 */ |
|
990 var $tree_data = array( |
|
991 '1'=> array( |
|
992 'link' => array( 'menu_name' => 'main-menu', 'mlid' => 1, 'hidden'=>0, 'has_children' => 1, 'title' => 'Item 1', 'in_active_trail' => 1, 'access'=>1, 'href' => 'a', 'localized_options' => array('attributes' => array('title' =>'')) ), |
|
993 'below' => array( |
|
994 '2' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 2, 'hidden'=>0, 'has_children' => 1, 'title' => 'Item 2', 'in_active_trail' => 1, 'access'=>1, 'href' => 'a/b', 'localized_options' => array('attributes' => array('title' =>'')) ), |
|
995 'below' => array( |
|
996 '3' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 3, 'hidden'=>0, 'has_children' => 0, 'title' => 'Item 3', 'in_active_trail' => 0, 'access'=>1, 'href' => 'a/b/c', 'localized_options' => array('attributes' => array('title' =>'')) ), |
|
997 'below' => array() ), |
|
998 '4' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 4, 'hidden'=>0, 'has_children' => 0, 'title' => 'Item 4', 'in_active_trail' => 0, 'access'=>1, 'href' => 'a/b/d', 'localized_options' => array('attributes' => array('title' =>'')) ), |
|
999 'below' => array() ) |
|
1000 ) |
|
1001 ) |
|
1002 ) |
|
1003 ), |
|
1004 '5' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 5, 'hidden'=>1, 'has_children' => 0, 'title' => 'Item 5', 'in_active_trail' => 0, 'access'=>1, 'href' => 'e', 'localized_options' => array('attributes' => array('title' =>'')) ), 'below' => array( ) ), |
|
1005 '6' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 6, 'hidden'=>0, 'has_children' => 0, 'title' => 'Item 6', 'in_active_trail' => 0, 'access'=>0, 'href' => 'f', 'localized_options' => array('attributes' => array('title' =>'')) ), 'below' => array( ) ), |
|
1006 '7' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 7, 'hidden'=>0, 'has_children' => 0, 'title' => 'Item 7', 'in_active_trail' => 0, 'access'=>1, 'href' => 'g', 'localized_options' => array('attributes' => array('title' =>'')) ), 'below' => array( ) ) |
|
1007 ); |
|
1008 |
|
1009 public static function getInfo() { |
|
1010 return array( |
|
1011 'name' => 'Menu tree output', |
|
1012 'description' => 'Tests menu tree output functions.', |
|
1013 'group' => 'Menu', |
|
1014 ); |
|
1015 } |
|
1016 |
|
1017 function setUp() { |
|
1018 parent::setUp(); |
|
1019 } |
|
1020 |
|
1021 /** |
|
1022 * Validate the generation of a proper menu tree output. |
|
1023 */ |
|
1024 function testMenuTreeData() { |
|
1025 $output = menu_tree_output($this->tree_data); |
|
1026 |
|
1027 // Validate that the - in main-menu is changed into an underscore |
|
1028 $this->assertEqual($output['1']['#theme'], 'menu_link__main_menu', 'Hyphen is changed to an underscore on menu_link'); |
|
1029 $this->assertEqual($output['#theme_wrappers'][0], 'menu_tree__main_menu', 'Hyphen is changed to an underscore on menu_tree wrapper'); |
|
1030 // Looking for child items in the data |
|
1031 $this->assertEqual( $output['1']['#below']['2']['#href'], 'a/b', 'Checking the href on a child item'); |
|
1032 $this->assertTrue( in_array('active-trail',$output['1']['#below']['2']['#attributes']['class']) , 'Checking the active trail class'); |
|
1033 // Validate that the hidden and no access items are missing |
|
1034 $this->assertFalse( isset($output['5']), 'Hidden item should be missing'); |
|
1035 $this->assertFalse( isset($output['6']), 'False access should be missing'); |
|
1036 // Item 7 is after a couple hidden items. Just to make sure that 5 and 6 are skipped and 7 still included |
|
1037 $this->assertTrue( isset($output['7']), 'Item after hidden items is present'); |
|
1038 } |
|
1039 } |
|
1040 |
|
1041 /** |
|
1042 * Menu breadcrumbs related tests. |
|
1043 */ |
|
1044 class MenuBreadcrumbTestCase extends MenuWebTestCase { |
|
1045 public static function getInfo() { |
|
1046 return array( |
|
1047 'name' => 'Breadcrumbs', |
|
1048 'description' => 'Tests breadcrumbs functionality.', |
|
1049 'group' => 'Menu', |
|
1050 ); |
|
1051 } |
|
1052 |
|
1053 function setUp() { |
|
1054 $modules = func_get_args(); |
|
1055 if (isset($modules[0]) && is_array($modules[0])) { |
|
1056 $modules = $modules[0]; |
|
1057 } |
|
1058 $modules[] = 'menu_test'; |
|
1059 parent::setUp($modules); |
|
1060 $perms = array_keys(module_invoke_all('permission')); |
|
1061 $this->admin_user = $this->drupalCreateUser($perms); |
|
1062 $this->drupalLogin($this->admin_user); |
|
1063 |
|
1064 // This test puts menu links in the Navigation menu and then tests for |
|
1065 // their presence on the page, so we need to ensure that the Navigation |
|
1066 // block will be displayed in all active themes. |
|
1067 db_update('block') |
|
1068 ->fields(array( |
|
1069 // Use a region that is valid for all themes. |
|
1070 'region' => 'content', |
|
1071 'status' => 1, |
|
1072 )) |
|
1073 ->condition('module', 'system') |
|
1074 ->condition('delta', 'navigation') |
|
1075 ->execute(); |
|
1076 } |
|
1077 |
|
1078 /** |
|
1079 * Tests breadcrumbs on node and administrative paths. |
|
1080 */ |
|
1081 function testBreadCrumbs() { |
|
1082 // Prepare common base breadcrumb elements. |
|
1083 $home = array('<front>' => 'Home'); |
|
1084 $admin = $home + array('admin' => t('Administration')); |
|
1085 $config = $admin + array('admin/config' => t('Configuration')); |
|
1086 $type = 'article'; |
|
1087 $langcode = LANGUAGE_NONE; |
|
1088 |
|
1089 // Verify breadcrumbs for default local tasks. |
|
1090 $expected = array( |
|
1091 'menu-test' => t('Menu test root'), |
|
1092 ); |
|
1093 $title = t('Breadcrumbs test: Local tasks'); |
|
1094 $trail = $home + $expected; |
|
1095 $tree = $expected + array( |
|
1096 'menu-test/breadcrumb/tasks' => $title, |
|
1097 ); |
|
1098 $this->assertBreadcrumb('menu-test/breadcrumb/tasks', $trail, $title, $tree); |
|
1099 $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first', $trail, $title, $tree); |
|
1100 $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first/first', $trail, $title, $tree); |
|
1101 $trail += array( |
|
1102 'menu-test/breadcrumb/tasks' => t('Breadcrumbs test: Local tasks'), |
|
1103 ); |
|
1104 $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first/second', $trail, $title, $tree); |
|
1105 $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second', $trail, $title, $tree); |
|
1106 $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second/first', $trail, $title, $tree); |
|
1107 $trail += array( |
|
1108 'menu-test/breadcrumb/tasks/second' => t('Second'), |
|
1109 ); |
|
1110 $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second/second', $trail, $title, $tree); |
|
1111 |
|
1112 // Verify Taxonomy administration breadcrumbs. |
|
1113 $trail = $admin + array( |
|
1114 'admin/structure' => t('Structure'), |
|
1115 ); |
|
1116 $this->assertBreadcrumb('admin/structure/taxonomy', $trail); |
|
1117 |
|
1118 $trail += array( |
|
1119 'admin/structure/taxonomy' => t('Taxonomy'), |
|
1120 ); |
|
1121 $this->assertBreadcrumb('admin/structure/taxonomy/tags', $trail); |
|
1122 $trail += array( |
|
1123 'admin/structure/taxonomy/tags' => t('Tags'), |
|
1124 ); |
|
1125 $this->assertBreadcrumb('admin/structure/taxonomy/tags/edit', $trail); |
|
1126 $this->assertBreadcrumb('admin/structure/taxonomy/tags/fields', $trail); |
|
1127 $this->assertBreadcrumb('admin/structure/taxonomy/tags/add', $trail); |
|
1128 |
|
1129 // Verify Menu administration breadcrumbs. |
|
1130 $trail = $admin + array( |
|
1131 'admin/structure' => t('Structure'), |
|
1132 ); |
|
1133 $this->assertBreadcrumb('admin/structure/menu', $trail); |
|
1134 |
|
1135 $trail += array( |
|
1136 'admin/structure/menu' => t('Menus'), |
|
1137 ); |
|
1138 $this->assertBreadcrumb('admin/structure/menu/manage/navigation', $trail); |
|
1139 $trail += array( |
|
1140 'admin/structure/menu/manage/navigation' => t('Navigation'), |
|
1141 ); |
|
1142 $this->assertBreadcrumb("admin/structure/menu/item/6/edit", $trail); |
|
1143 $this->assertBreadcrumb('admin/structure/menu/manage/navigation/edit', $trail); |
|
1144 $this->assertBreadcrumb('admin/structure/menu/manage/navigation/add', $trail); |
|
1145 |
|
1146 // Verify Node administration breadcrumbs. |
|
1147 $trail = $admin + array( |
|
1148 'admin/structure' => t('Structure'), |
|
1149 'admin/structure/types' => t('Content types'), |
|
1150 ); |
|
1151 $this->assertBreadcrumb('admin/structure/types/add', $trail); |
|
1152 $this->assertBreadcrumb("admin/structure/types/manage/$type", $trail); |
|
1153 $trail += array( |
|
1154 "admin/structure/types/manage/$type" => t('Article'), |
|
1155 ); |
|
1156 $this->assertBreadcrumb("admin/structure/types/manage/$type/fields", $trail); |
|
1157 $this->assertBreadcrumb("admin/structure/types/manage/$type/display", $trail); |
|
1158 $trail_teaser = $trail + array( |
|
1159 "admin/structure/types/manage/$type/display" => t('Manage display'), |
|
1160 ); |
|
1161 $this->assertBreadcrumb("admin/structure/types/manage/$type/display/teaser", $trail_teaser); |
|
1162 $this->assertBreadcrumb("admin/structure/types/manage/$type/comment/fields", $trail); |
|
1163 $this->assertBreadcrumb("admin/structure/types/manage/$type/comment/display", $trail); |
|
1164 $this->assertBreadcrumb("admin/structure/types/manage/$type/delete", $trail); |
|
1165 $trail += array( |
|
1166 "admin/structure/types/manage/$type/fields" => t('Manage fields'), |
|
1167 ); |
|
1168 $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/body", $trail); |
|
1169 $trail += array( |
|
1170 "admin/structure/types/manage/$type/fields/body" => t('Body'), |
|
1171 ); |
|
1172 $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/body/widget-type", $trail); |
|
1173 |
|
1174 // Verify Filter text format administration breadcrumbs. |
|
1175 $format = db_query_range("SELECT format, name FROM {filter_format}", 1, 1)->fetch(); |
|
1176 $format_id = $format->format; |
|
1177 $trail = $config + array( |
|
1178 'admin/config/content' => t('Content authoring'), |
|
1179 ); |
|
1180 $this->assertBreadcrumb('admin/config/content/formats', $trail); |
|
1181 |
|
1182 $trail += array( |
|
1183 'admin/config/content/formats' => t('Text formats'), |
|
1184 ); |
|
1185 $this->assertBreadcrumb('admin/config/content/formats/add', $trail); |
|
1186 $this->assertBreadcrumb("admin/config/content/formats/$format_id", $trail); |
|
1187 $trail += array( |
|
1188 "admin/config/content/formats/$format_id" => $format->name, |
|
1189 ); |
|
1190 $this->assertBreadcrumb("admin/config/content/formats/$format_id/disable", $trail); |
|
1191 |
|
1192 // Verify node breadcrumbs (without menu link). |
|
1193 $node1 = $this->drupalCreateNode(); |
|
1194 $nid1 = $node1->nid; |
|
1195 $trail = $home; |
|
1196 $this->assertBreadcrumb("node/$nid1", $trail); |
|
1197 // Also verify that the node does not appear elsewhere (e.g., menu trees). |
|
1198 $this->assertNoLink($node1->title); |
|
1199 // The node itself should not be contained in the breadcrumb on the default |
|
1200 // local task, since there is no difference between both pages. |
|
1201 $this->assertBreadcrumb("node/$nid1/view", $trail); |
|
1202 // Also verify that the node does not appear elsewhere (e.g., menu trees). |
|
1203 $this->assertNoLink($node1->title); |
|
1204 |
|
1205 $trail += array( |
|
1206 "node/$nid1" => $node1->title, |
|
1207 ); |
|
1208 $this->assertBreadcrumb("node/$nid1/edit", $trail); |
|
1209 |
|
1210 // Verify that breadcrumb on node listing page contains "Home" only. |
|
1211 $trail = array(); |
|
1212 $this->assertBreadcrumb('node', $trail); |
|
1213 |
|
1214 // Verify node breadcrumbs (in menu). |
|
1215 // Do this separately for Main menu and Navigation menu, since only the |
|
1216 // latter is a preferred menu by default. |
|
1217 // @todo Also test all themes? Manually testing led to the suspicion that |
|
1218 // breadcrumbs may differ, possibly due to template.php overrides. |
|
1219 $menus = array('main-menu', 'navigation'); |
|
1220 // Alter node type menu settings. |
|
1221 variable_set("menu_options_$type", $menus); |
|
1222 variable_set("menu_parent_$type", 'navigation:0'); |
|
1223 |
|
1224 foreach ($menus as $menu) { |
|
1225 // Create a parent node in the current menu. |
|
1226 $title = $this->randomName(); |
|
1227 $node2 = $this->drupalCreateNode(array( |
|
1228 'type' => $type, |
|
1229 'title' => $title, |
|
1230 'menu' => array( |
|
1231 'enabled' => 1, |
|
1232 'link_title' => 'Parent ' . $title, |
|
1233 'description' => '', |
|
1234 'menu_name' => $menu, |
|
1235 'plid' => 0, |
|
1236 ), |
|
1237 )); |
|
1238 $nid2 = $node2->nid; |
|
1239 |
|
1240 $trail = $home; |
|
1241 $tree = array( |
|
1242 "node/$nid2" => $node2->menu['link_title'], |
|
1243 ); |
|
1244 $this->assertBreadcrumb("node/$nid2", $trail, $node2->title, $tree); |
|
1245 // The node itself should not be contained in the breadcrumb on the |
|
1246 // default local task, since there is no difference between both pages. |
|
1247 $this->assertBreadcrumb("node/$nid2/view", $trail, $node2->title, $tree); |
|
1248 $trail += array( |
|
1249 "node/$nid2" => $node2->menu['link_title'], |
|
1250 ); |
|
1251 $this->assertBreadcrumb("node/$nid2/edit", $trail); |
|
1252 |
|
1253 // Create a child node in the current menu. |
|
1254 $title = $this->randomName(); |
|
1255 $node3 = $this->drupalCreateNode(array( |
|
1256 'type' => $type, |
|
1257 'title' => $title, |
|
1258 'menu' => array( |
|
1259 'enabled' => 1, |
|
1260 'link_title' => 'Child ' . $title, |
|
1261 'description' => '', |
|
1262 'menu_name' => $menu, |
|
1263 'plid' => $node2->menu['mlid'], |
|
1264 ), |
|
1265 )); |
|
1266 $nid3 = $node3->nid; |
|
1267 |
|
1268 $this->assertBreadcrumb("node/$nid3", $trail, $node3->title, $tree, FALSE); |
|
1269 // The node itself should not be contained in the breadcrumb on the |
|
1270 // default local task, since there is no difference between both pages. |
|
1271 $this->assertBreadcrumb("node/$nid3/view", $trail, $node3->title, $tree, FALSE); |
|
1272 $trail += array( |
|
1273 "node/$nid3" => $node3->menu['link_title'], |
|
1274 ); |
|
1275 $tree += array( |
|
1276 "node/$nid3" => $node3->menu['link_title'], |
|
1277 ); |
|
1278 $this->assertBreadcrumb("node/$nid3/edit", $trail); |
|
1279 |
|
1280 // Verify that node listing page still contains "Home" only. |
|
1281 $trail = array(); |
|
1282 $this->assertBreadcrumb('node', $trail); |
|
1283 |
|
1284 if ($menu == 'navigation') { |
|
1285 $parent = $node2; |
|
1286 $child = $node3; |
|
1287 } |
|
1288 } |
|
1289 |
|
1290 // Create a Navigation menu link for 'node', move the last parent node menu |
|
1291 // link below it, and verify a full breadcrumb for the last child node. |
|
1292 $menu = 'navigation'; |
|
1293 $edit = array( |
|
1294 'link_title' => 'Root', |
|
1295 'link_path' => 'node', |
|
1296 ); |
|
1297 $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save')); |
|
1298 $link = db_query('SELECT * FROM {menu_links} WHERE link_title = :title', array(':title' => 'Root'))->fetchAssoc(); |
|
1299 |
|
1300 $edit = array( |
|
1301 'menu[parent]' => $link['menu_name'] . ':' . $link['mlid'], |
|
1302 ); |
|
1303 $this->drupalPost("node/{$parent->nid}/edit", $edit, t('Save')); |
|
1304 $expected = array( |
|
1305 "node" => $link['link_title'], |
|
1306 ); |
|
1307 $trail = $home + $expected; |
|
1308 $tree = $expected + array( |
|
1309 "node/{$parent->nid}" => $parent->menu['link_title'], |
|
1310 ); |
|
1311 $this->assertBreadcrumb(NULL, $trail, $parent->title, $tree); |
|
1312 $trail += array( |
|
1313 "node/{$parent->nid}" => $parent->menu['link_title'], |
|
1314 ); |
|
1315 $tree += array( |
|
1316 "node/{$child->nid}" => $child->menu['link_title'], |
|
1317 ); |
|
1318 $this->assertBreadcrumb("node/{$child->nid}", $trail, $child->title, $tree); |
|
1319 |
|
1320 // Add a taxonomy term/tag to last node, and add a link for that term to the |
|
1321 // Navigation menu. |
|
1322 $tags = array( |
|
1323 'Drupal' => array(), |
|
1324 'Breadcrumbs' => array(), |
|
1325 ); |
|
1326 $edit = array( |
|
1327 "field_tags[$langcode]" => implode(',', array_keys($tags)), |
|
1328 ); |
|
1329 $this->drupalPost("node/{$parent->nid}/edit", $edit, t('Save')); |
|
1330 |
|
1331 // Put both terms into a hierarchy Drupal » Breadcrumbs. Required for both |
|
1332 // the menu links and the terms itself, since taxonomy_term_page() resets |
|
1333 // the breadcrumb based on taxonomy term hierarchy. |
|
1334 $parent_tid = 0; |
|
1335 foreach ($tags as $name => $null) { |
|
1336 $terms = taxonomy_term_load_multiple(NULL, array('name' => $name)); |
|
1337 $term = reset($terms); |
|
1338 $tags[$name]['term'] = $term; |
|
1339 if ($parent_tid) { |
|
1340 $edit = array( |
|
1341 'parent[]' => array($parent_tid), |
|
1342 ); |
|
1343 $this->drupalPost("taxonomy/term/{$term->tid}/edit", $edit, t('Save')); |
|
1344 } |
|
1345 $parent_tid = $term->tid; |
|
1346 } |
|
1347 $parent_mlid = 0; |
|
1348 foreach ($tags as $name => $data) { |
|
1349 $term = $data['term']; |
|
1350 $edit = array( |
|
1351 'link_title' => "$name link", |
|
1352 'link_path' => "taxonomy/term/{$term->tid}", |
|
1353 'parent' => "$menu:{$parent_mlid}", |
|
1354 ); |
|
1355 $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save')); |
|
1356 $tags[$name]['link'] = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array( |
|
1357 ':title' => $edit['link_title'], |
|
1358 ':href' => $edit['link_path'], |
|
1359 ))->fetchAssoc(); |
|
1360 $tags[$name]['link']['link_path'] = $edit['link_path']; |
|
1361 $parent_mlid = $tags[$name]['link']['mlid']; |
|
1362 } |
|
1363 |
|
1364 // Verify expected breadcrumbs for menu links. |
|
1365 $trail = $home; |
|
1366 $tree = array(); |
|
1367 foreach ($tags as $name => $data) { |
|
1368 $term = $data['term']; |
|
1369 $link = $data['link']; |
|
1370 |
|
1371 $tree += array( |
|
1372 $link['link_path'] => $link['link_title'], |
|
1373 ); |
|
1374 $this->assertBreadcrumb($link['link_path'], $trail, $term->name, $tree); |
|
1375 $this->assertRaw(check_plain($parent->title), 'Tagged node found.'); |
|
1376 |
|
1377 // Additionally make sure that this link appears only once; i.e., the |
|
1378 // untranslated menu links automatically generated from menu router items |
|
1379 // ('taxonomy/term/%') should never be translated and appear in any menu |
|
1380 // other than the breadcrumb trail. |
|
1381 $elements = $this->xpath('//div[@id=:menu]/descendant::a[@href=:href]', array( |
|
1382 ':menu' => 'block-system-navigation', |
|
1383 ':href' => url($link['link_path']), |
|
1384 )); |
|
1385 $this->assertTrue(count($elements) == 1, "Link to {$link['link_path']} appears only once."); |
|
1386 |
|
1387 // Next iteration should expect this tag as parent link. |
|
1388 // Note: Term name, not link name, due to taxonomy_term_page(). |
|
1389 $trail += array( |
|
1390 $link['link_path'] => $term->name, |
|
1391 ); |
|
1392 } |
|
1393 |
|
1394 // Verify breadcrumbs on user and user/%. |
|
1395 // We need to log back in and out below, and cannot simply grant the |
|
1396 // 'administer users' permission, since user_page() makes your head explode. |
|
1397 user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array( |
|
1398 'access user profiles', |
|
1399 )); |
|
1400 $this->drupalLogout(); |
|
1401 |
|
1402 // Verify breadcrumb on front page. |
|
1403 $this->assertBreadcrumb('<front>', array()); |
|
1404 |
|
1405 // Verify breadcrumb on user pages (without menu link) for anonymous user. |
|
1406 $trail = $home; |
|
1407 $this->assertBreadcrumb('user', $trail, t('User account')); |
|
1408 $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $this->admin_user->name); |
|
1409 |
|
1410 // Verify breadcrumb on user pages (without menu link) for registered users. |
|
1411 $this->drupalLogin($this->admin_user); |
|
1412 $trail = $home; |
|
1413 $this->assertBreadcrumb('user', $trail, $this->admin_user->name); |
|
1414 $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $this->admin_user->name); |
|
1415 $trail += array( |
|
1416 'user/' . $this->admin_user->uid => $this->admin_user->name, |
|
1417 ); |
|
1418 $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $this->admin_user->name); |
|
1419 |
|
1420 // Create a second user to verify breadcrumb on user pages again. |
|
1421 $this->web_user = $this->drupalCreateUser(array( |
|
1422 'administer users', |
|
1423 'access user profiles', |
|
1424 )); |
|
1425 $this->drupalLogin($this->web_user); |
|
1426 |
|
1427 // Verify correct breadcrumb and page title on another user's account pages |
|
1428 // (without menu link). |
|
1429 $trail = $home; |
|
1430 $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $this->admin_user->name); |
|
1431 $trail += array( |
|
1432 'user/' . $this->admin_user->uid => $this->admin_user->name, |
|
1433 ); |
|
1434 $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $this->admin_user->name); |
|
1435 |
|
1436 // Verify correct breadcrumb and page title when viewing own user account |
|
1437 // pages (without menu link). |
|
1438 $trail = $home; |
|
1439 $this->assertBreadcrumb('user/' . $this->web_user->uid, $trail, $this->web_user->name); |
|
1440 $trail += array( |
|
1441 'user/' . $this->web_user->uid => $this->web_user->name, |
|
1442 ); |
|
1443 $this->assertBreadcrumb('user/' . $this->web_user->uid . '/edit', $trail, $this->web_user->name); |
|
1444 |
|
1445 // Add a Navigation menu links for 'user' and $this->admin_user. |
|
1446 // Although it may be faster to manage these links via low-level API |
|
1447 // functions, there's a lot that can go wrong in doing so. |
|
1448 $this->drupalLogin($this->admin_user); |
|
1449 $edit = array( |
|
1450 'link_title' => 'User', |
|
1451 'link_path' => 'user', |
|
1452 ); |
|
1453 $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save')); |
|
1454 $link_user = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array( |
|
1455 ':title' => $edit['link_title'], |
|
1456 ':href' => $edit['link_path'], |
|
1457 ))->fetchAssoc(); |
|
1458 |
|
1459 $edit = array( |
|
1460 'link_title' => $this->admin_user->name . ' link', |
|
1461 'link_path' => 'user/' . $this->admin_user->uid, |
|
1462 ); |
|
1463 $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save')); |
|
1464 $link_admin_user = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array( |
|
1465 ':title' => $edit['link_title'], |
|
1466 ':href' => $edit['link_path'], |
|
1467 ))->fetchAssoc(); |
|
1468 |
|
1469 // Verify expected breadcrumbs for the two separate links. |
|
1470 $this->drupalLogout(); |
|
1471 $trail = $home; |
|
1472 $tree = array( |
|
1473 $link_user['link_path'] => $link_user['link_title'], |
|
1474 ); |
|
1475 $this->assertBreadcrumb('user', $trail, $link_user['link_title'], $tree); |
|
1476 $tree = array( |
|
1477 $link_admin_user['link_path'] => $link_admin_user['link_title'], |
|
1478 ); |
|
1479 $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $link_admin_user['link_title'], $tree); |
|
1480 |
|
1481 $this->drupalLogin($this->admin_user); |
|
1482 $trail += array( |
|
1483 $link_admin_user['link_path'] => $link_admin_user['link_title'], |
|
1484 ); |
|
1485 $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $link_admin_user['link_title'], $tree, FALSE); |
|
1486 |
|
1487 // Move 'user/%' below 'user' and verify again. |
|
1488 $edit = array( |
|
1489 'parent' => "$menu:{$link_user['mlid']}", |
|
1490 ); |
|
1491 $this->drupalPost("admin/structure/menu/item/{$link_admin_user['mlid']}/edit", $edit, t('Save')); |
|
1492 |
|
1493 $this->drupalLogout(); |
|
1494 $trail = $home; |
|
1495 $tree = array( |
|
1496 $link_user['link_path'] => $link_user['link_title'], |
|
1497 ); |
|
1498 $this->assertBreadcrumb('user', $trail, $link_user['link_title'], $tree); |
|
1499 $trail += array( |
|
1500 $link_user['link_path'] => $link_user['link_title'], |
|
1501 ); |
|
1502 $tree += array( |
|
1503 $link_admin_user['link_path'] => $link_admin_user['link_title'], |
|
1504 ); |
|
1505 $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $link_admin_user['link_title'], $tree); |
|
1506 |
|
1507 $this->drupalLogin($this->admin_user); |
|
1508 $trail += array( |
|
1509 $link_admin_user['link_path'] => $link_admin_user['link_title'], |
|
1510 ); |
|
1511 $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $link_admin_user['link_title'], $tree, FALSE); |
|
1512 |
|
1513 // Create an only slightly privileged user being able to access site reports |
|
1514 // but not administration pages. |
|
1515 $this->web_user = $this->drupalCreateUser(array( |
|
1516 'access site reports', |
|
1517 )); |
|
1518 $this->drupalLogin($this->web_user); |
|
1519 |
|
1520 // Verify that we can access recent log entries, there is a corresponding |
|
1521 // page title, and that the breadcrumb is empty (because the user is not |
|
1522 // able to access "Administer", so the trail cannot recurse into it). |
|
1523 $trail = array(); |
|
1524 $this->assertBreadcrumb('admin', $trail, t('Access denied')); |
|
1525 $this->assertResponse(403); |
|
1526 |
|
1527 $trail = $home; |
|
1528 $this->assertBreadcrumb('admin/reports', $trail, t('Reports')); |
|
1529 $this->assertNoResponse(403); |
|
1530 |
|
1531 $this->assertBreadcrumb('admin/reports/dblog', $trail, t('Recent log messages')); |
|
1532 $this->assertNoResponse(403); |
|
1533 } |
|
1534 } |
|
1535 |
|
1536 /** |
|
1537 * Tests active menu trails. |
|
1538 */ |
|
1539 class MenuTrailTestCase extends MenuWebTestCase { |
|
1540 public static function getInfo() { |
|
1541 return array( |
|
1542 'name' => 'Active trail', |
|
1543 'description' => 'Tests active menu trails and alteration functionality.', |
|
1544 'group' => 'Menu', |
|
1545 ); |
|
1546 } |
|
1547 |
|
1548 function setUp() { |
|
1549 $modules = func_get_args(); |
|
1550 if (isset($modules[0]) && is_array($modules[0])) { |
|
1551 $modules = $modules[0]; |
|
1552 } |
|
1553 $modules[] = 'menu_test'; |
|
1554 parent::setUp($modules); |
|
1555 $this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'access administration pages')); |
|
1556 $this->drupalLogin($this->admin_user); |
|
1557 |
|
1558 // This test puts menu links in the Navigation menu and then tests for |
|
1559 // their presence on the page, so we need to ensure that the Navigation |
|
1560 // block will be displayed in all active themes. |
|
1561 db_update('block') |
|
1562 ->fields(array( |
|
1563 // Use a region that is valid for all themes. |
|
1564 'region' => 'content', |
|
1565 'status' => 1, |
|
1566 )) |
|
1567 ->condition('module', 'system') |
|
1568 ->condition('delta', 'navigation') |
|
1569 ->execute(); |
|
1570 |
|
1571 // This test puts menu links in the Management menu and then tests for |
|
1572 // their presence on the page, so we need to ensure that the Management |
|
1573 // block will be displayed in all active themes. |
|
1574 db_update('block') |
|
1575 ->fields(array( |
|
1576 // Use a region that is valid for all themes. |
|
1577 'region' => 'content', |
|
1578 'status' => 1, |
|
1579 )) |
|
1580 ->condition('module', 'system') |
|
1581 ->condition('delta', 'management') |
|
1582 ->execute(); |
|
1583 } |
|
1584 |
|
1585 /** |
|
1586 * Tests active trails are properly affected by menu_tree_set_path(). |
|
1587 */ |
|
1588 function testMenuTreeSetPath() { |
|
1589 $home = array('<front>' => 'Home'); |
|
1590 $config_tree = array( |
|
1591 'admin' => t('Administration'), |
|
1592 'admin/config' => t('Configuration'), |
|
1593 ); |
|
1594 $config = $home + $config_tree; |
|
1595 |
|
1596 // The menu_test_menu_tree_set_path system variable controls whether or not |
|
1597 // the menu_test_menu_trail_callback() callback (used by all paths in these |
|
1598 // tests) issues an overriding call to menu_trail_set_path(). |
|
1599 $test_menu_path = array( |
|
1600 'menu_name' => 'management', |
|
1601 'path' => 'admin/config/system/site-information', |
|
1602 ); |
|
1603 |
|
1604 $breadcrumb = $home + array( |
|
1605 'menu-test' => t('Menu test root'), |
|
1606 ); |
|
1607 $tree = array( |
|
1608 'menu-test' => t('Menu test root'), |
|
1609 'menu-test/menu-trail' => t('Menu trail - Case 1'), |
|
1610 ); |
|
1611 |
|
1612 // Test the tree generation for the Navigation menu. |
|
1613 variable_del('menu_test_menu_tree_set_path'); |
|
1614 $this->assertBreadcrumb('menu-test/menu-trail', $breadcrumb, t('Menu trail - Case 1'), $tree); |
|
1615 |
|
1616 // Override the active trail for the Management tree; it should not affect |
|
1617 // the Navigation tree. |
|
1618 variable_set('menu_test_menu_tree_set_path', $test_menu_path); |
|
1619 $this->assertBreadcrumb('menu-test/menu-trail', $breadcrumb, t('Menu trail - Case 1'), $tree); |
|
1620 |
|
1621 $breadcrumb = $config + array( |
|
1622 'admin/config/development' => t('Development'), |
|
1623 ); |
|
1624 $tree = $config_tree + array( |
|
1625 'admin/config/development' => t('Development'), |
|
1626 'admin/config/development/menu-trail' => t('Menu trail - Case 2'), |
|
1627 ); |
|
1628 |
|
1629 $override_breadcrumb = $config + array( |
|
1630 'admin/config/system' => t('System'), |
|
1631 'admin/config/system/site-information' => t('Site information'), |
|
1632 ); |
|
1633 $override_tree = $config_tree + array( |
|
1634 'admin/config/system' => t('System'), |
|
1635 'admin/config/system/site-information' => t('Site information'), |
|
1636 ); |
|
1637 |
|
1638 // Test the tree generation for the Management menu. |
|
1639 variable_del('menu_test_menu_tree_set_path'); |
|
1640 $this->assertBreadcrumb('admin/config/development/menu-trail', $breadcrumb, t('Menu trail - Case 2'), $tree); |
|
1641 |
|
1642 // Override the active trail for the Management tree; it should affect the |
|
1643 // breadcrumbs and Management tree. |
|
1644 variable_set('menu_test_menu_tree_set_path', $test_menu_path); |
|
1645 $this->assertBreadcrumb('admin/config/development/menu-trail', $override_breadcrumb, t('Menu trail - Case 2'), $override_tree); |
|
1646 } |
|
1647 |
|
1648 /** |
|
1649 * Tests that the active trail works correctly on custom 403 and 404 pages. |
|
1650 */ |
|
1651 function testCustom403And404Pages() { |
|
1652 // Set the custom 403 and 404 pages we will use. |
|
1653 variable_set('site_403', 'menu-test/custom-403-page'); |
|
1654 variable_set('site_404', 'menu-test/custom-404-page'); |
|
1655 |
|
1656 // Define the paths we'll visit to trigger 403 and 404 responses during |
|
1657 // this test, and the expected active trail for each case. |
|
1658 $paths = array( |
|
1659 403 => 'admin/config', |
|
1660 404 => $this->randomName(), |
|
1661 ); |
|
1662 // For the 403 page, the initial trail during the Drupal bootstrap should |
|
1663 // include the page that the user is trying to visit, while the final trail |
|
1664 // should reflect the custom 403 page that the user was redirected to. |
|
1665 $expected_trail[403]['initial'] = array( |
|
1666 '<front>' => 'Home', |
|
1667 'admin/config' => 'Configuration', |
|
1668 ); |
|
1669 $expected_trail[403]['final'] = array( |
|
1670 '<front>' => 'Home', |
|
1671 'menu-test' => 'Menu test root', |
|
1672 'menu-test/custom-403-page' => 'Custom 403 page', |
|
1673 ); |
|
1674 // For the 404 page, the initial trail during the Drupal bootstrap should |
|
1675 // only contain the link back to "Home" (since the page the user is trying |
|
1676 // to visit doesn't have any menu items associated with it), while the |
|
1677 // final trail should reflect the custom 404 page that the user was |
|
1678 // redirected to. |
|
1679 $expected_trail[404]['initial'] = array( |
|
1680 '<front>' => 'Home', |
|
1681 ); |
|
1682 $expected_trail[404]['final'] = array( |
|
1683 '<front>' => 'Home', |
|
1684 'menu-test' => 'Menu test root', |
|
1685 'menu-test/custom-404-page' => 'Custom 404 page', |
|
1686 ); |
|
1687 |
|
1688 // Visit each path as an anonymous user so that we will actually get a 403 |
|
1689 // on admin/config. |
|
1690 $this->drupalLogout(); |
|
1691 foreach (array(403, 404) as $status_code) { |
|
1692 // Before visiting the page, trigger the code in the menu_test module |
|
1693 // that will record the active trail (so we can check it in this test). |
|
1694 variable_set('menu_test_record_active_trail', TRUE); |
|
1695 $this->drupalGet($paths[$status_code]); |
|
1696 $this->assertResponse($status_code); |
|
1697 |
|
1698 // Check that the initial trail (during the Drupal bootstrap) matches |
|
1699 // what we expect. |
|
1700 $initial_trail = variable_get('menu_test_active_trail_initial', array()); |
|
1701 $this->assertEqual(count($initial_trail), count($expected_trail[$status_code]['initial']), format_string('The initial active trail for a @status_code page contains the expected number of items (expected: @expected, found: @found).', array( |
|
1702 '@status_code' => $status_code, |
|
1703 '@expected' => count($expected_trail[$status_code]['initial']), |
|
1704 '@found' => count($initial_trail), |
|
1705 ))); |
|
1706 foreach (array_keys($expected_trail[$status_code]['initial']) as $index => $path) { |
|
1707 $this->assertEqual($initial_trail[$index]['href'], $path, format_string('Element number @number of the initial active trail for a @status_code page contains the correct path (expected: @expected, found: @found)', array( |
|
1708 '@number' => $index + 1, |
|
1709 '@status_code' => $status_code, |
|
1710 '@expected' => $path, |
|
1711 '@found' => $initial_trail[$index]['href'], |
|
1712 ))); |
|
1713 } |
|
1714 |
|
1715 // Check that the final trail (after the user has been redirected to the |
|
1716 // custom 403/404 page) matches what we expect. |
|
1717 $final_trail = variable_get('menu_test_active_trail_final', array()); |
|
1718 $this->assertEqual(count($final_trail), count($expected_trail[$status_code]['final']), format_string('The final active trail for a @status_code page contains the expected number of items (expected: @expected, found: @found).', array( |
|
1719 '@status_code' => $status_code, |
|
1720 '@expected' => count($expected_trail[$status_code]['final']), |
|
1721 '@found' => count($final_trail), |
|
1722 ))); |
|
1723 foreach (array_keys($expected_trail[$status_code]['final']) as $index => $path) { |
|
1724 $this->assertEqual($final_trail[$index]['href'], $path, format_string('Element number @number of the final active trail for a @status_code page contains the correct path (expected: @expected, found: @found)', array( |
|
1725 '@number' => $index + 1, |
|
1726 '@status_code' => $status_code, |
|
1727 '@expected' => $path, |
|
1728 '@found' => $final_trail[$index]['href'], |
|
1729 ))); |
|
1730 } |
|
1731 |
|
1732 // Check that the breadcrumb displayed on the final custom 403/404 page |
|
1733 // matches what we expect. (The last item of the active trail represents |
|
1734 // the current page, which is not supposed to appear in the breadcrumb, |
|
1735 // so we need to remove it from the array before checking.) |
|
1736 array_pop($expected_trail[$status_code]['final']); |
|
1737 $this->assertBreadcrumb(NULL, $expected_trail[$status_code]['final']); |
|
1738 } |
|
1739 } |
|
1740 } |