#550254: tests for menu links reparenting.

From: Damien Tournoud <damien@commerceguys.com>


---
 simpletest/tests/menu.test |  212 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 212 insertions(+), 0 deletions(-)

diff --git modules/simpletest/tests/menu.test modules/simpletest/tests/menu.test
index 22f7146..79cc61e 100644
--- modules/simpletest/tests/menu.test
+++ modules/simpletest/tests/menu.test
@@ -434,6 +434,218 @@ class MenuRouterTestCase extends DrupalWebTestCase {
 }
 
 /**
+ * Tests for menu links.
+ */
+class MenuLinksUnitTestCase extends DrupalWebTestCase {
+  // Use the lightweight testing profile for this test.
+  protected $profile = 'testing';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Menu links',
+      'description' => 'Test handling of menu links hierarchies.',
+      'group' => 'Menu',
+    );
+  }
+
+  /**
+   * Create a simple hierarchy of links.
+   */
+  function createLinkHierarchy($module = 'menu_test') {
+    // First remove all the menu links.
+    db_truncate('menu_links')->execute();
+
+    // Then create a simple link hierarchy:
+    // - $parent
+    //   - $child-1
+    //      - $child-1-1
+    //      - $child-1-2
+    //   - $child-2
+    $base_options = array(
+      'link_title' => 'Menu link test',
+      'module' => $module,
+      'menu_name' => 'menu_test',
+    );
+
+    $links['parent'] = $base_options + array(
+      'link_path' => 'menu-test/parent',
+    );
+    menu_link_save($links['parent']);
+
+    $links['child-1'] = $base_options + array(
+      'link_path' => 'menu-test/parent/child-1',
+      'plid' => $links['parent']['mlid'],
+    );
+    menu_link_save($links['child-1']);
+
+    $links['child-1-1'] = $base_options + array(
+      'link_path' => 'menu-test/parent/child-1/child-1-1',
+      'plid' => $links['child-1']['mlid'],
+    );
+    menu_link_save($links['child-1-1']);
+
+    $links['child-1-2'] = $base_options + array(
+      'link_path' => 'menu-test/parent/child-1/child-1-2',
+      'plid' => $links['child-1']['mlid'],
+    );
+    menu_link_save($links['child-1-2']);
+
+    $links['child-2'] = $base_options + array(
+      'link_path' => 'menu-test/parent/child-2',
+      'plid' => $links['parent']['mlid'],
+    );
+    menu_link_save($links['child-2']);
+
+    return $links;
+  }
+
+  /**
+   * Assert that at set of links is properly parented.
+   */
+  function assertMenuLinkParents($links, $expected_hierarchy) {
+    foreach ($expected_hierarchy as $child => $parent) {
+      $mlid = $links[$child]['mlid'];
+      $plid = $parent ? $links[$parent]['mlid'] : 0;
+
+      $menu_link = menu_link_load($mlid);
+      menu_link_save($menu_link);
+      $this->assertEqual($menu_link['plid'], $plid, t('Menu link %mlid has parent of %plid, expected %expected_plid.', array('%mlid' => $mlid, '%plid' => $menu_link['plid'], '%expected_plid' => $plid)));
+    }
+  }
+
+  /**
+   * Test automatic reparenting of menu links.
+   */
+  function testMenuLinkReparenting($module = 'menu_test') {
+    // Check the initial hierarchy.
+    $links = $this->createLinkHierarchy($module);
+
+    $expected_hierarchy = array(
+      'parent' => FALSE,
+      'child-1' => 'parent',
+      'child-1-1' => 'child-1',
+      'child-1-2' => 'child-1',
+      'child-2' => 'parent',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+
+    // Start over, and move child-1 under child-2, and check that all the
+    // childs of child-1 have been moved too.
+    $links = $this->createLinkHierarchy($module);
+    $links['child-1']['plid'] = $links['child-2']['mlid'];
+    menu_link_save($links['child-1']);
+
+    $expected_hierarchy = array(
+      'parent' => FALSE,
+      'child-1' => 'child-2',
+      'child-1-1' => 'child-1',
+      'child-1-2' => 'child-1',
+      'child-2' => 'parent',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+
+    // Start over, and delete child-1, and check that the children of child-1
+    // have been reassigned to the parent. menu_link_delete() will cowardly
+    // refuse to delete a menu link defined by the system module, so skip the
+    // test in that case.
+    if ($module != 'system') {
+      $links = $this->createLinkHierarchy($module);
+      menu_link_delete($links['child-1']['mlid']);
+
+      $expected_hierarchy = array(
+        'parent' => FALSE,
+        'child-1-1' => 'parent',
+        'child-1-2' => 'parent',
+        'child-2' => 'parent',
+      );
+      $this->assertMenuLinkParents($links, $expected_hierarchy);
+    }
+
+    // Start over, forcefully delete child-1 from the database, and check
+    // that the children of child-1 have been reassigned to the parent,
+    // going up on the old path hierarchy stored in each of the links.
+    $links = $this->createLinkHierarchy($module);
+    db_delete('menu_links')
+      ->condition('mlid', $links['child-1']['mlid'])
+      ->execute();
+
+    $expected_hierarchy = array(
+      'parent' => FALSE,
+      'child-1-1' => 'parent',
+      'child-1-2' => 'parent',
+      'child-2' => 'parent',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+
+    // Start over, forcefully delete the parent from the database, and check
+    // that the children of parent are now top-level.
+    $links = $this->createLinkHierarchy($module);
+    db_delete('menu_links')
+      ->condition('mlid', $links['parent']['mlid'])
+      ->execute();
+
+    $expected_hierarchy = array(
+      'child-1-1' => 'child-1',
+      'child-1-2' => 'child-1',
+      'child-2' => FALSE,
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+  }
+
+  /**
+   * Test automatic reparenting of menu links derived from menu routers.
+   */
+  function testMenuLinkRouterReparenting() {
+    // Run all the standard parenting tests on menu links derived from
+    // menu routers.
+    $this->testMenuLinkReparenting('system');
+
+    // Additionnaly, test reparenting based on path.
+    $links = $this->createLinkHierarchy('system');
+
+    // Move child-1-2 has a child of child-2, making the link hierarchy
+    // inconsistent with the path hierarchy.
+    $links['child-1-2']['plid'] = $links['child-2']['mlid'];
+    menu_link_save($links['child-1-2']);
+
+    // Check the new hierarchy.
+    $expected_hierarchy = array(
+      'parent' => FALSE,
+      'child-1' => 'parent',
+      'child-1-1' => 'child-1',
+      'child-2' => 'parent',
+      'child-1-2' => 'child-2',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+
+    // Now delete 'parent': 'child-1' and 'child-2' should get moved to the
+    // top-level.
+    db_delete('menu_links')
+      ->condition('mlid', $links['parent']['mlid'])
+      ->execute();
+    $expected_hierarchy = array(
+      'child-1' => FALSE,
+      'child-1-1' => 'child-1',
+      'child-2' => FALSE,
+      'child-1-2' => 'child-2',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+
+    // Now delete 'child-2', 'child-1-2' will get reparented under 'child-1'
+    // based on its path.
+    db_delete('menu_links')
+      ->condition('mlid', $links['child-2']['mlid'])
+      ->execute();
+    $expected_hierarchy = array(
+      'child-1' => FALSE,
+      'child-1-1' => 'child-1',
+      'child-1-2' => 'child-1',
+    );
+    $this->assertMenuLinkParents($links, $expected_hierarchy);
+  }
+}
+
+/**
  * Tests rebuilding the menu by setting 'menu_rebuild_needed.'
  */
 class MenuRebuildTestCase extends DrupalWebTestCase {
