cms/drupal/modules/simpletest/tests/module.test
changeset 541 e756a8c72c3d
equal deleted inserted replaced
540:07239de796bb 541:e756a8c72c3d
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * @file
       
     5  * Tests for the module API.
       
     6  */
       
     7 
       
     8 /**
       
     9  * Unit tests for the module API.
       
    10  */
       
    11 class ModuleUnitTest extends DrupalWebTestCase {
       
    12   public static function getInfo() {
       
    13     return array(
       
    14       'name' => 'Module API',
       
    15       'description' => 'Test low-level module functions.',
       
    16       'group' => 'Module',
       
    17     );
       
    18   }
       
    19 
       
    20   /**
       
    21    * The basic functionality of module_list().
       
    22    */
       
    23   function testModuleList() {
       
    24     // Build a list of modules, sorted alphabetically.
       
    25     $profile_info = install_profile_info('standard', 'en');
       
    26     $module_list = $profile_info['dependencies'];
       
    27 
       
    28     // Installation profile is a module that is expected to be loaded.
       
    29     $module_list[] = 'standard';
       
    30 
       
    31     sort($module_list);
       
    32     // Compare this list to the one returned by module_list(). We expect them
       
    33     // to match, since all default profile modules have a weight equal to 0
       
    34     // (except for block.module, which has a lower weight but comes first in
       
    35     // the alphabet anyway).
       
    36     $this->assertModuleList($module_list, t('Standard profile'));
       
    37 
       
    38     // Try to install a new module.
       
    39     module_enable(array('contact'));
       
    40     $module_list[] = 'contact';
       
    41     sort($module_list);
       
    42     $this->assertModuleList($module_list, t('After adding a module'));
       
    43 
       
    44     // Try to mess with the module weights.
       
    45     db_update('system')
       
    46       ->fields(array('weight' => 20))
       
    47       ->condition('name', 'contact')
       
    48       ->condition('type', 'module')
       
    49       ->execute();
       
    50     // Reset the module list.
       
    51     module_list(TRUE);
       
    52     // Move contact to the end of the array.
       
    53     unset($module_list[array_search('contact', $module_list)]);
       
    54     $module_list[] = 'contact';
       
    55     $this->assertModuleList($module_list, t('After changing weights'));
       
    56 
       
    57     // Test the fixed list feature.
       
    58     $fixed_list = array(
       
    59       'system' => array('filename' => drupal_get_path('module', 'system')),
       
    60       'menu' => array('filename' => drupal_get_path('module', 'menu')),
       
    61     );
       
    62     module_list(FALSE, FALSE, FALSE, $fixed_list);
       
    63     $new_module_list = array_combine(array_keys($fixed_list), array_keys($fixed_list));
       
    64     $this->assertModuleList($new_module_list, t('When using a fixed list'));
       
    65 
       
    66     // Reset the module list.
       
    67     module_list(TRUE);
       
    68     $this->assertModuleList($module_list, t('After reset'));
       
    69   }
       
    70 
       
    71   /**
       
    72    * Assert that module_list() return the expected values.
       
    73    *
       
    74    * @param $expected_values
       
    75    *   The expected values, sorted by weight and module name.
       
    76    */
       
    77   protected function assertModuleList(Array $expected_values, $condition) {
       
    78     $expected_values = array_combine($expected_values, $expected_values);
       
    79     $this->assertEqual($expected_values, module_list(), format_string('@condition: module_list() returns correct results', array('@condition' => $condition)));
       
    80     ksort($expected_values);
       
    81     $this->assertIdentical($expected_values, module_list(FALSE, FALSE, TRUE), format_string('@condition: module_list() returns correctly sorted results', array('@condition' => $condition)));
       
    82   }
       
    83 
       
    84   /**
       
    85    * Test module_implements() caching.
       
    86    */
       
    87   function testModuleImplements() {
       
    88     // Clear the cache.
       
    89     cache_clear_all('module_implements', 'cache_bootstrap');
       
    90     $this->assertFalse(cache_get('module_implements', 'cache_bootstrap'), 'The module implements cache is empty.');
       
    91     $this->drupalGet('');
       
    92     $this->assertTrue(cache_get('module_implements', 'cache_bootstrap'), 'The module implements cache is populated after requesting a page.');
       
    93 
       
    94     // Test again with an authenticated user.
       
    95     $this->user = $this->drupalCreateUser();
       
    96     $this->drupalLogin($this->user);
       
    97     cache_clear_all('module_implements', 'cache_bootstrap');
       
    98     $this->drupalGet('');
       
    99     $this->assertTrue(cache_get('module_implements', 'cache_bootstrap'), 'The module implements cache is populated after requesting a page.');
       
   100 
       
   101     // Make sure group include files are detected properly even when the file is
       
   102     // already loaded when the cache is rebuilt.
       
   103     // For that activate the module_test which provides the file to load.
       
   104     module_enable(array('module_test'));
       
   105 
       
   106     module_load_include('inc', 'module_test', 'module_test.file');
       
   107     $modules = module_implements('test_hook');
       
   108     $static = drupal_static('module_implements');
       
   109     $this->assertTrue(in_array('module_test', $modules), 'Hook found.');
       
   110     $this->assertEqual($static['test_hook']['module_test'], 'file', 'Include file detected.');
       
   111   }
       
   112 
       
   113   /**
       
   114    * Test that module_invoke() can load a hook defined in hook_hook_info().
       
   115    */
       
   116   function testModuleInvoke() {
       
   117     module_enable(array('module_test'), FALSE);
       
   118     $this->resetAll();
       
   119     $this->drupalGet('module-test/hook-dynamic-loading-invoke');
       
   120     $this->assertText('success!', 'module_invoke() dynamically loads a hook defined in hook_hook_info().');
       
   121   }
       
   122 
       
   123   /**
       
   124    * Test that module_invoke_all() can load a hook defined in hook_hook_info().
       
   125    */
       
   126   function testModuleInvokeAll() {
       
   127     module_enable(array('module_test'), FALSE);
       
   128     $this->resetAll();
       
   129     $this->drupalGet('module-test/hook-dynamic-loading-invoke-all');
       
   130     $this->assertText('success!', 'module_invoke_all() dynamically loads a hook defined in hook_hook_info().');
       
   131   }
       
   132 
       
   133   /**
       
   134    * Test dependency resolution.
       
   135    */
       
   136   function testDependencyResolution() {
       
   137     // Enable the test module, and make sure that other modules we are testing
       
   138     // are not already enabled. (If they were, the tests below would not work
       
   139     // correctly.)
       
   140     module_enable(array('module_test'), FALSE);
       
   141     $this->assertTrue(module_exists('module_test'), 'Test module is enabled.');
       
   142     $this->assertFalse(module_exists('forum'), 'Forum module is disabled.');
       
   143     $this->assertFalse(module_exists('poll'), 'Poll module is disabled.');
       
   144     $this->assertFalse(module_exists('php'), 'PHP module is disabled.');
       
   145 
       
   146     // First, create a fake missing dependency. Forum depends on poll, which
       
   147     // depends on a made-up module, foo. Nothing should be installed.
       
   148     variable_set('dependency_test', 'missing dependency');
       
   149     drupal_static_reset('system_rebuild_module_data');
       
   150     $result = module_enable(array('forum'));
       
   151     $this->assertFalse($result, 'module_enable() returns FALSE if dependencies are missing.');
       
   152     $this->assertFalse(module_exists('forum'), 'module_enable() aborts if dependencies are missing.');
       
   153 
       
   154     // Now, fix the missing dependency. Forum module depends on poll, but poll
       
   155     // depends on the PHP module. module_enable() should work.
       
   156     variable_set('dependency_test', 'dependency');
       
   157     drupal_static_reset('system_rebuild_module_data');
       
   158     $result = module_enable(array('forum'));
       
   159     $this->assertTrue($result, 'module_enable() returns the correct value.');
       
   160     // Verify that the fake dependency chain was installed.
       
   161     $this->assertTrue(module_exists('poll') && module_exists('php'), 'Dependency chain was installed by module_enable().');
       
   162     // Verify that the original module was installed.
       
   163     $this->assertTrue(module_exists('forum'), 'Module installation with unlisted dependencies succeeded.');
       
   164     // Finally, verify that the modules were enabled in the correct order.
       
   165     $this->assertEqual(variable_get('test_module_enable_order', array()), array('php', 'poll', 'forum'), 'Modules were enabled in the correct order by module_enable().');
       
   166 
       
   167     // Now, disable the PHP module. Both forum and poll should be disabled as
       
   168     // well, in the correct order.
       
   169     module_disable(array('php'));
       
   170     $this->assertTrue(!module_exists('forum') && !module_exists('poll'), 'Depedency chain was disabled by module_disable().');
       
   171     $this->assertFalse(module_exists('php'), 'Disabling a module with unlisted dependents succeeded.');
       
   172     $this->assertEqual(variable_get('test_module_disable_order', array()), array('forum', 'poll', 'php'), 'Modules were disabled in the correct order by module_disable().');
       
   173 
       
   174     // Disable a module that is listed as a dependency by the installation
       
   175     // profile. Make sure that the profile itself is not on the list of
       
   176     // dependent modules to be disabled.
       
   177     $profile = drupal_get_profile();
       
   178     $info = install_profile_info($profile);
       
   179     $this->assertTrue(in_array('comment', $info['dependencies']), 'Comment module is listed as a dependency of the installation profile.');
       
   180     $this->assertTrue(module_exists('comment'), 'Comment module is enabled.');
       
   181     module_disable(array('comment'));
       
   182     $this->assertFalse(module_exists('comment'), 'Comment module was disabled.');
       
   183     $disabled_modules = variable_get('test_module_disable_order', array());
       
   184     $this->assertTrue(in_array('comment', $disabled_modules), 'Comment module is in the list of disabled modules.');
       
   185     $this->assertFalse(in_array($profile, $disabled_modules), 'The installation profile is not in the list of disabled modules.');
       
   186 
       
   187     // Try to uninstall the PHP module by itself. This should be rejected,
       
   188     // since the modules which it depends on need to be uninstalled first, and
       
   189     // that is too destructive to perform automatically.
       
   190     $result = drupal_uninstall_modules(array('php'));
       
   191     $this->assertFalse($result, 'Calling drupal_uninstall_modules() on a module whose dependents are not uninstalled fails.');
       
   192     foreach (array('forum', 'poll', 'php') as $module) {
       
   193       $this->assertNotEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, format_string('The @module module was not uninstalled.', array('@module' => $module)));
       
   194     }
       
   195 
       
   196     // Now uninstall all three modules explicitly, but in the incorrect order,
       
   197     // and make sure that drupal_uninstal_modules() uninstalled them in the
       
   198     // correct sequence.
       
   199     $result = drupal_uninstall_modules(array('poll', 'php', 'forum'));
       
   200     $this->assertTrue($result, 'drupal_uninstall_modules() returns the correct value.');
       
   201     foreach (array('forum', 'poll', 'php') as $module) {
       
   202       $this->assertEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, format_string('The @module module was uninstalled.', array('@module' => $module)));
       
   203     }
       
   204     $this->assertEqual(variable_get('test_module_uninstall_order', array()), array('forum', 'poll', 'php'), 'Modules were uninstalled in the correct order by drupal_uninstall_modules().');
       
   205 
       
   206     // Uninstall the profile module from above, and make sure that the profile
       
   207     // itself is not on the list of dependent modules to be uninstalled.
       
   208     $result = drupal_uninstall_modules(array('comment'));
       
   209     $this->assertTrue($result, 'drupal_uninstall_modules() returns the correct value.');
       
   210     $this->assertEqual(drupal_get_installed_schema_version('comment'), SCHEMA_UNINSTALLED, 'Comment module was uninstalled.');
       
   211     $uninstalled_modules = variable_get('test_module_uninstall_order', array());
       
   212     $this->assertTrue(in_array('comment', $uninstalled_modules), 'Comment module is in the list of uninstalled modules.');
       
   213     $this->assertFalse(in_array($profile, $uninstalled_modules), 'The installation profile is not in the list of uninstalled modules.');
       
   214 
       
   215     // Enable forum module again, which should enable both the poll module and
       
   216     // php module. But, this time do it with poll module declaring a dependency
       
   217     // on a specific version of php module in its info file. Make sure that
       
   218     // module_enable() still works.
       
   219     variable_set('dependency_test', 'version dependency');
       
   220     drupal_static_reset('system_rebuild_module_data');
       
   221     $result = module_enable(array('forum'));
       
   222     $this->assertTrue($result, 'module_enable() returns the correct value.');
       
   223     // Verify that the fake dependency chain was installed.
       
   224     $this->assertTrue(module_exists('poll') && module_exists('php'), 'Dependency chain was installed by module_enable().');
       
   225     // Verify that the original module was installed.
       
   226     $this->assertTrue(module_exists('forum'), 'Module installation with version dependencies succeeded.');
       
   227     // Finally, verify that the modules were enabled in the correct order.
       
   228     $enable_order = variable_get('test_module_enable_order', array());
       
   229     $php_position = array_search('php', $enable_order);
       
   230     $poll_position = array_search('poll', $enable_order);
       
   231     $forum_position = array_search('forum', $enable_order);
       
   232     $php_before_poll = $php_position !== FALSE && $poll_position !== FALSE && $php_position < $poll_position;
       
   233     $poll_before_forum = $poll_position !== FALSE && $forum_position !== FALSE && $poll_position < $forum_position;
       
   234     $this->assertTrue($php_before_poll && $poll_before_forum, 'Modules were enabled in the correct order by module_enable().');
       
   235   }
       
   236 }
       
   237 
       
   238 /**
       
   239  * Unit tests for module installation.
       
   240  */
       
   241 class ModuleInstallTestCase extends DrupalWebTestCase {
       
   242   public static function getInfo() {
       
   243     return array(
       
   244       'name' => 'Module installation',
       
   245       'description' => 'Tests the installation of modules.',
       
   246       'group' => 'Module',
       
   247     );
       
   248   }
       
   249 
       
   250   function setUp() {
       
   251     parent::setUp('module_test');
       
   252   }
       
   253 
       
   254   /**
       
   255    * Test that calls to drupal_write_record() work during module installation.
       
   256    *
       
   257    * This is a useful function to test because modules often use it to insert
       
   258    * initial data in their database tables when they are being installed or
       
   259    * enabled. Furthermore, drupal_write_record() relies on the module schema
       
   260    * information being available, so this also checks that the data from one of
       
   261    * the module's hook implementations, in particular hook_schema(), is
       
   262    * properly available during this time. Therefore, this test helps ensure
       
   263    * that modules are fully functional while Drupal is installing and enabling
       
   264    * them.
       
   265    */
       
   266   function testDrupalWriteRecord() {
       
   267     // Check for data that was inserted using drupal_write_record() while the
       
   268     // 'module_test' module was being installed and enabled.
       
   269     $data = db_query("SELECT data FROM {module_test}")->fetchCol();
       
   270     $this->assertTrue(in_array('Data inserted in hook_install()', $data), 'Data inserted using drupal_write_record() in hook_install() is correctly saved.');
       
   271     $this->assertTrue(in_array('Data inserted in hook_enable()', $data), 'Data inserted using drupal_write_record() in hook_enable() is correctly saved.');
       
   272   }
       
   273 }
       
   274 
       
   275 /**
       
   276  * Unit tests for module uninstallation and related hooks.
       
   277  */
       
   278 class ModuleUninstallTestCase extends DrupalWebTestCase {
       
   279   public static function getInfo() {
       
   280     return array(
       
   281       'name' => 'Module uninstallation',
       
   282       'description' => 'Tests the uninstallation of modules.',
       
   283       'group' => 'Module',
       
   284     );
       
   285   }
       
   286 
       
   287   function setUp() {
       
   288     parent::setUp('module_test', 'user');
       
   289   }
       
   290 
       
   291   /**
       
   292    * Tests the hook_modules_uninstalled() of the user module.
       
   293    */
       
   294   function testUserPermsUninstalled() {
       
   295     // Uninstalls the module_test module, so hook_modules_uninstalled()
       
   296     // is executed.
       
   297     module_disable(array('module_test'));
       
   298     drupal_uninstall_modules(array('module_test'));
       
   299 
       
   300     // Are the perms defined by module_test removed from {role_permission}.
       
   301     $count = db_query("SELECT COUNT(rid) FROM {role_permission} WHERE permission = :perm", array(':perm' => 'module_test perm'))->fetchField();
       
   302     $this->assertEqual(0, $count, 'Permissions were all removed.');
       
   303   }
       
   304 }
       
   305 
       
   306 class ModuleImplementsAlterTestCase extends DrupalWebTestCase {
       
   307   public static function getInfo() {
       
   308     return array(
       
   309       'name' => 'Module implements alter',
       
   310       'description' => 'Tests hook_module_implements_alter().',
       
   311       'group' => 'Module',
       
   312     );
       
   313   }
       
   314 
       
   315   /**
       
   316    * Tests hook_module_implements_alter() adding an implementation.
       
   317    */
       
   318   function testModuleImplementsAlter() {
       
   319     module_enable(array('module_test'), FALSE);
       
   320     $this->assertTrue(module_exists('module_test'), 'Test module is enabled.');
       
   321 
       
   322     // Assert that module_test.module is now included.
       
   323     $this->assertTrue(function_exists('module_test_permission'),
       
   324       'The file module_test.module was successfully included.');
       
   325 
       
   326     $modules = module_implements('permission');
       
   327     $this->assertTrue(in_array('module_test', $modules), 'module_test implements hook_permission.');
       
   328 
       
   329     $modules = module_implements('module_implements_alter');
       
   330     $this->assertTrue(in_array('module_test', $modules), 'module_test implements hook_module_implements_alter().');
       
   331 
       
   332     // Assert that module_test.implementations.inc is not included yet.
       
   333     $this->assertFalse(function_exists('module_test_altered_test_hook'),
       
   334       'The file module_test.implementations.inc is not included yet.');
       
   335 
       
   336     // Assert that module_test_module_implements_alter(*, 'altered_test_hook')
       
   337     // has added an implementation
       
   338     $this->assertTrue(in_array('module_test', module_implements('altered_test_hook')),
       
   339       'module_test implements hook_altered_test_hook().');
       
   340 
       
   341     // Assert that module_test.implementations.inc was included as part of the process.
       
   342     $this->assertTrue(function_exists('module_test_altered_test_hook'),
       
   343       'The file module_test.implementations.inc was included.');
       
   344   }
       
   345 
       
   346 }