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	28 Jun 2009 19:28:45 -0000
@@ -77,3 +77,33 @@ 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 defined 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/simpletest/tests/module_test.info
===================================================================
RCS file: modules/simpletest/tests/module_test.info
diff -N modules/simpletest/tests/module_test.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/module_test.info	28 Jun 2009 19:28:45 -0000
@@ -0,0 +1,8 @@
+; $Id$
+name = "Module test"
+description = "Support module for module system testing."
+package = Testing
+version = VERSION
+core = 7.x
+files[] = module_test.module
+hidden = TRUE
Index: modules/simpletest/tests/module_test.module
===================================================================
RCS file: modules/simpletest/tests/module_test.module
diff -N modules/simpletest/tests/module_test.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/module_test.module	28 Jun 2009 19:28:45 -0000
@@ -0,0 +1,11 @@
+<?php
+// $Id$
+
+/**
+ * Implement hook_perm().
+ */
+function module_test_perm() {
+  return array(
+    'module_test perm' => t('example perm for module_test module'),
+  );
+}
Index: modules/system/system.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.test,v
retrieving revision 1.53
diff -u -p -r1.53 system.test
--- modules/system/system.test	28 Jun 2009 03:56:43 -0000	1.53
+++ modules/system/system.test	28 Jun 2009 19:28:45 -0000
@@ -149,6 +149,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	28 Jun 2009 19:28:45 -0000
@@ -945,3 +945,18 @@ function user_modules_installed($modules
     }
   }
 }
+
+/**
+ * Implement hook_modules_uninstalled().
+ */
+function user_modules_uninstalled($modules) {
+  $permissions = array();
+  foreach ($modules as $module) {
+    $permissions = array_merge($permissions, array_keys(module_invoke($module, 'perm')));
+  }
+  if (!empty($permissions)) {
+    db_delete('role_permission')
+      ->condition('permission', $permissions, 'IN')
+      ->execute();
+  }
+}
