Index: modules/simpletest/tests/module.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/module.test,v
retrieving revision 1.6
diff -u -p -r1.6 module.test
--- modules/simpletest/tests/module.test	20 Jun 2009 06:00:24 -0000	1.6
+++ modules/simpletest/tests/module.test	27 Jun 2009 14:41:36 -0000
@@ -77,3 +77,34 @@ class ModuleUnitTest extends DrupalWebTe
     $this->assertIdentical($expected_values, module_list(FALSE, TRUE), t('@condition: module_list() returns correctly sorted results', array('@condition' => $condition)));
   }
 }
+
+/**
+ * Unit tests for module uninstallation and related hooks.
+ */
+class ModuleUninstallTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('Module uninstallation'),
+      'description' => t('Checks module uninstallation'),
+      'group' => t('Module'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('module_test', 'user');
+  }
+
+  /**
+   * Tests the hook_modules_uninstalled() of the user module.
+   */
+  function testUserPermsUninstalled() {
+    // Uninstalls the module_test module, so hook_modules_uninstalled()
+    // is executed.
+    drupal_uninstall_modules(array('module_test'));
+
+    // Are the perms definced by module_test removed from {role_permission}.
+    $count = db_query("SELECT COUNT(rid) FROM {role_permission} WHERE permission = :perm",
+      array(':perm' => 'module_test perm'))->fetchField();
+    $this->assertEqual(0, $count, t('Permissions were all removed.'));
+  }
+}
Index: modules/system/system.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.test,v
retrieving revision 1.50
diff -u -p -r1.50 system.test
--- modules/system/system.test	13 Jun 2009 21:08:31 -0000	1.50
+++ modules/system/system.test	27 Jun 2009 14:41:38 -0000
@@ -148,6 +148,12 @@ class EnableDisableTestCase extends Modu
     $this->assertModules(array('aggregator'), FALSE);
     $this->assertTableCount('aggregator', FALSE);
     $this->assertLogMessage('system', "%module module uninstalled.", array('%module' => 'aggregator'), WATCHDOG_INFO);
+
+    // Reinstall (and enable) aggregator module.
+    $edit = array();
+    $edit['modules[Core][aggregator][enable]'] = 'aggregator';
+    $this->drupalPost('admin/build/modules', $edit, t('Save configuration'));
+    $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
   }
 }
 
Index: modules/user/user.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v
retrieving revision 1.58
diff -u -p -r1.58 user.admin.inc
--- modules/user/user.admin.inc	15 Jun 2009 09:49:58 -0000	1.58
+++ modules/user/user.admin.inc	27 Jun 2009 14:41:40 -0000
@@ -945,3 +945,19 @@ function user_modules_installed($modules
     }
   }
 }
+
+/**
+ * Implementation of hook_modules_uninstalled().
+ */
+function user_modules_uninstalled($modules) {
+  $permissions = array();
+  foreach ($modules as $module) {
+    drupal_load('module', $module);
+    $permissions = array_merge($permissions, array_keys(module_invoke($module, 'perm')));
+  }
+  if (!empty($permissions)) {
+    db_delete('role_permission')
+      ->condition('permission', $permissions, 'IN')
+      ->execute();
+  }
+}
