From cb481742663ea96fe4163bcceb777307e1bd8b8c Mon Sep 17 00:00:00 2001 From: "Eloy Lafuente (stronk7)" Date: Sat, 14 Apr 2012 05:03:13 +0200 Subject: [PATCH] MDL-32587 phpunit: new option to create distributed phpunit.xml files --- admin/tool/phpunit/cli/util.php | 28 ++++-- lib/phpunit/lib.php | 164 ++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 9 deletions(-) diff --git a/admin/tool/phpunit/cli/util.php b/admin/tool/phpunit/cli/util.php index cced963ecf2..137e9183a23 100644 --- a/admin/tool/phpunit/cli/util.php +++ b/admin/tool/phpunit/cli/util.php @@ -34,13 +34,14 @@ require_once(__DIR__.'/../../../../lib/phpunit/bootstraplib.php'); // now get cli options list($options, $unrecognized) = cli_get_params( array( - 'drop' => false, - 'install' => false, - 'buildconfig' => false, - 'diag' => false, - 'phpunitdir' => false, - 'run' => false, - 'help' => false, + 'drop' => false, + 'install' => false, + 'buildconfig' => false, + 'buildconfigdist' => false, + 'diag' => false, + 'phpunitdir' => false, + 'run' => false, + 'help' => false, ), array( 'h' => 'help' @@ -105,14 +106,16 @@ $diag = $options['diag']; $drop = $options['drop']; $install = $options['install']; $buildconfig = $options['buildconfig']; +$buildconfigdist = $options['buildconfigdist']; -if ($options['help'] or (!$drop and !$install and !$buildconfig and !$diag)) { +if ($options['help'] or (!$drop and !$install and !$buildconfig and !$buildconfigdist and !$diag)) { $help = "Various PHPUnit utility functions Options: --drop Drop database and dataroot --install Install database --buildconfig Build /phpunit.xml from /phpunit.xml.dist that includes suites for all plugins and core +--buildconfigdist Build distributed phpunit.xml files for each plugin and subsystem --diag Diagnose installation and return error code only --run Execute PHPUnit tests (alternative for standard phpunit binary) @@ -136,7 +139,14 @@ if ($diag) { if (phpunit_util::build_config_file()) { exit(0); } else { - phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, 'Can not create phpunit.xml configuration file, verify dirroot permissions'); + phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, 'Can not create main phpunit.xml configuration file, verify dirroot permissions'); + } + +} else if ($buildconfigdist) { + if (phpunit_util::build_distributed_config_files()) { + exit(0); + } else { + phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, 'Can not create main phpunit.xml configuration file, verify dirroot permissions'); } } else if ($drop) { diff --git a/lib/phpunit/lib.php b/lib/phpunit/lib.php index 40de0f01546..a0fd0a4402b 100644 --- a/lib/phpunit/lib.php +++ b/lib/phpunit/lib.php @@ -886,6 +886,170 @@ class phpunit_util { return (bool)$result; } + + /** + * Builds distributed phpunit.xml and dataroot/phpunit/webrunner.xml files using defaults from /phpunit.xml.dist + * + * @static + * @return bool true means all config files created, false means only dataroot file created + */ + public static function build_distributed_config_files() { + global $CFG; + + $template = ' + + + @dir@ + + '; + + // Use the upstream file as source for the distributed configurations + $ftemplate = file_get_contents("$CFG->dirroot/phpunit.xml.dist"); + $ftemplate = preg_replace('|lib/phpunit/bootstrap.php|', $CFG->dirroot . '/lib/phpunit/bootstrap.php', $ftemplate); + $ftemplate = preg_replace('|', $ftemplate); + + // Get all the components + $components = self::get_all_plugins_with_tests() + self::get_all_subsystems_with_tests(); + + // Get all the directories having tests + $directories = self::get_all_directories_with_tests(); + + // Find any directory not covered by proper components + $remaining = array_diff($directories, $components); + + // Add them to the list of components + $components += $remaining; + + // Create the corresponding phpunit.xml file for each component + foreach ($components as $cname => $cpath) { + // Calculate the component suite + $ctemplate = $template; + $ctemplate = str_replace('@component@', $cname, $ctemplate); + $ctemplate = str_replace('@dir@', $cpath, $ctemplate); + + // Apply it to the file template + $fcontents = str_replace('', $ctemplate, $ftemplate); + + // Write the file + $result = false; + if (is_writable($cpath)) { + if ($result = (bool)file_put_contents("$cpath/phpunit.xml", $fcontents)) { + phpunit_boostrap_fix_file_permissions("$cpath/phpunit.xml"); + } + } + // Problems writing file, throw error + if (!$result) { + phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, "Can not create $cpath/phpunit.xml configuration file, verify dir permissions"); + } + } + + // Finally, build the main config file too + return self::build_config_file(); + } + + /** + * Returns all the plugins having phpunit tests + * + * @return array all the plugins having phpunit tests + * + */ + private static function get_all_plugins_with_tests() { + $pluginswithtests = array(); + + $plugintypes = get_plugin_types(); + ksort($plugintypes); + foreach ($plugintypes as $type => $unused) { + $plugs = get_plugin_list($type); + ksort($plugs); + foreach ($plugs as $plug => $fullplug) { + // Look for tests recursively + if (self::directory_has_tests($fullplug)) { + $pluginswithtests[$type . '_' . $plug] = $fullplug; + } + } + } + return $pluginswithtests; + } + + /** + * Returns all the subsystems having phpunit tests + * + * Note we are hacking here the list of subsystems + * to cover some well-known subsystems that are not properly + * returned by the {@link get_core_subsystems()} function. + * + * @return array all the subsystems having phpunit tests + */ + private static function get_all_subsystems_with_tests() { + global $CFG; + + $subsystemswithtests = array(); + + $subsystems = get_core_subsystems(); + + // Hack the list a bit to cover some well-known ones + $subsystems['backup'] = 'backup'; + $subsystems['db-dml'] = 'lib/dml'; + $subsystems['db-ddl'] = 'lib/ddl'; + + ksort($subsystems); + foreach ($subsystems as $subsys => $relsubsys) { + if ($relsubsys === null) { + continue; + } + $fullsubsys = $CFG->dirroot . '/' . $relsubsys; + if (!is_dir($fullsubsys)) { + continue; + } + // Look for tests recursively + if (self::directory_has_tests($fullsubsys)) { + $subsystemswithtests['core_' . $subsys] = $fullsubsys; + } + } + return $subsystemswithtests; + } + + /** + * Returns all the directories having tests + * + * @return array all directories having tests + */ + private static function get_all_directories_with_tests() { + global $CFG; + + $dirs = array(); + $dirite = new RecursiveDirectoryIterator($CFG->dirroot); + $iteite = new RecursiveIteratorIterator($dirite); + $regite = new RegexIterator($iteite, '|/tests/.*_test\.php$|'); + foreach ($regite as $path => $element) { + $key = dirname(dirname($path)); + $value = trim(str_replace('/', '_', str_replace($CFG->dirroot, '', $key)), '_'); + $dirs[$key] = $value; + } + ksort($dirs); + return array_flip($dirs); + } + + /** + * Returns if a given directory has tests (recursively) + * + * @param $dir string full path to the directory to look for phpunit tests + * @return bool if a given directory has tests (true) or no (false) + */ + private static function directory_has_tests($dir) { + if (!is_dir($dir)) { + return false; + } + + $dirite = new RecursiveDirectoryIterator($dir); + $iteite = new RecursiveIteratorIterator($dirite); + $regite = new RegexIterator($iteite, '|/tests/.*_test\.php$|'); + $regite->rewind(); + if ($regite->valid()) { + return true; + } + return false; + } }