MDL-19579 code coverage - add Spike PHPCoverage lib (LGPL)

This commit is contained in:
stronk7
2009-06-23 09:23:06 +00:00
parent 86cc669c1b
commit b5ba94e5a5
36 changed files with 6431 additions and 0 deletions
+327
View File
@@ -0,0 +1,327 @@
<?php
/*
* $Id$
*
* Copyright(c) 2004-2006, SpikeSource Inc. All Rights Reserved.
* Licensed under the Open Software License version 2.1
* (See http://www.spikesource.com/license.html)
*/
?>
<?php
/**
* This driver file can be used to initialize and generate PHPCoverage
* report when PHPCoverage is used with a non-PHP test tool - like HttpUnit
* It can, of course, be used for PHP test tools like SimpleTest and PHPUnit
*
* Notes:
* * Option parsing courtesy of "daevid at daevid dot com" (http://php.planetmirror.com/manual/en/function.getopt.php)
* * Originally contributed by Ed Espino <[email protected]>
*/
if(!defined("__PHPCOVERAGE_HOME")) {
define("__PHPCOVERAGE_HOME", dirname(dirname(__FILE__)));
}
require_once __PHPCOVERAGE_HOME . "/conf/phpcoverage.conf.php";
require_once __PHPCOVERAGE_HOME . "/util/Utility.php";
// ######################################################################
// ######################################################################
function usage() {
global $util;
echo "Usage: " . $_SERVER['argv'][0] . " <options>\n";
echo "\n";
echo " Options: \n";
echo " --phpcoverage-home <path> OR -p <path> Path to PHPCoverage home (defaults to PHPCOVERAGE_HOME environment property)\n";
echo " --init Initialize PHPCoverage Reporting\n";
echo " --report Generate PHPCoverage Report\n";
echo " --local Run and generate PHPCoverage report for local test run (Implies '--report')\n";
echo " --cleanup Remove existing PHPCoverage data\n";
echo " init options \n";
echo " --cov-url <url> Specify application default url\n";
echo " --tmp-dir <path> Specify tmp directory location (Defaults to '" . $util->getTmpDir() . "')\n";
echo " --cov-file-name <name> Specify coverage data file name (Defaults to 'phpcoverage.data.xml')\n";
echo " remote report options \n";
echo " --cov-data-files <path1,path2,...> Coverage data file path [use this instead of --cov-url for a local file path]\n";
echo " --report-name <name> Report name\n";
echo " --report-dir <path> Report directory path (Defaults to 'report')\n";
echo " --appbase-path <path> Application base path (Defaults to PHPCOVERAGE_APPBASE_PATH if specified on the command line)\n";
echo " --include-paths <path1,path2,...> Comma-separated paths to include in code coverage report. (Includes appbase-path by default)\n";
echo " --exclude-paths <path1,path2,...> Comma-separated paths to exclude from code coverage report.\n";
echo " --print-summary Print coverage report summary to console.\n";
echo " local report options \n";
echo " --report-name <name> Report name\n";
echo " --report-dir <path> Report directory path (Defaults to 'report')\n";
echo " --appbase-path <path> Application base path (Defaults to PHPCOVERAGE_APPBASE_PATH if specified on the command line)\n";
echo " --include-paths <path1,path2,...> Comma-separated paths to include in code coverage report.\n";
echo " --exclude-paths <path1,path2,...> Comma-separated paths to exclude from code coverage report.\n";
echo " --print-summary Print coverage report summary to console.\n";
echo " --test-driver <path> Path to the test driver file.\n";
echo " other options \n";
echo " --verbose OR -v Print verbose information\n";
echo " --help OR -h Display this usage information\n";
echo "";
echo " Sample Usage (local execution):\n";
echo " php driver.php --local --report \\ \n";
echo " -p /opt/phpcoverage/src \\ \n";
echo " --report-name 'Test Report' --report-dir /tmp/report \\ \n";
echo " --appbase-path /opt/phpcoverage/samples/local \\ \n";
echo " --test-driver /opt/phpcoverage/samples/local/test_driver.php \\ \n";
echo " --print-summary \n";
exit;
}
//
// Setup command line argument processing
//
$OPTION["p"] = false;
$OPTION['verbose'] = false;
$OPTION['init'] = false;
$OPTION['report'] = false;
$OPTION['cleanup'] = false;
$OPTION['cov-url'] = false;
$OPTION['report-name'] = false;
$OPTION['report-dir'] = false;
$OPTION['tmp-dir'] = false;
$OPTION['cov-file-name'] = false;
$OPTION['cov-data-files'] = false;
$OPTION['appbase-path'] = false;
$OPTION['local'] = false;
$OPTION['test-driver'] = false;
//
// loop through our arguments and see what the user selected
//
for ($i = 1; $i < $_SERVER["argc"]; $i++) {
switch($_SERVER["argv"][$i]) {
case "--phpcoverage-home":
case "-p":
$OPTION['p'] = $_SERVER['argv'][++$i];
break;
case "-v":
case "--verbose":
$OPTION['verbose'] = true;
break;
case "--init":
$OPTION['init'] = true;
break;
case "--report":
$OPTION['report'] = true;
break;
case "--local":
$OPTION['local'] = true;
$OPTION['report'] = true;
break;
case "--cleanup":
$OPTION['cleanup'] = true;
break;
case "--cov-url":
$OPTION['cov-url'] = $_SERVER['argv'][++$i] . "/" . "phpcoverage.remote.top.inc.php";
break;
case "--tmp-dir":
$OPTION['tmp-dir'] = $_SERVER['argv'][++$i];
break;
case "--cov-file-name":
$OPTION['cov-file-name'] = $_SERVER['argv'][++$i];
break;
case "--cov-data-files":
$OPTION['cov-data-files'] = $_SERVER['argv'][++$i];
break;
case "--report-name":
$OPTION['report-name'] = $_SERVER['argv'][++$i];
break;
case "--report-dir":
$OPTION['report-dir'] = $_SERVER['argv'][++$i];
break;
case "--appbase-path":
$OPTION['appbase-path'] = $_SERVER['argv'][++$i];
break;
case "--include-paths":
$OPTION['include-paths'] = $_SERVER['argv'][++$i];
break;
case "--exclude-paths":
$OPTION['exclude-paths'] = $_SERVER['argv'][++$i];
break;
case "--print-summary":
$OPTION['print-summary'] = true;
break;
case "--test-driver":
$OPTION['test-driver'] = $_SERVER['argv'][++$i];
break;
case "--help":
case "-h":
usage();
break;
}
}
if($OPTION['p'] == false) {
$OPTION['p'] = __PHPCOVERAGE_HOME;
if(empty($OPTION['p']) || !is_dir($OPTION['p'])) {
die("PHPCOVERAGE_HOME does not exist. [" . $OPTION['p'] . "]");
}
}
putenv("PHPCOVERAGE_HOME=" . $OPTION['p']);
require_once $OPTION['p'] . "/phpcoverage.inc.php";
require_once PHPCOVERAGE_HOME . "/remote/RemoteCoverageRecorder.php";
require_once PHPCOVERAGE_HOME . "/reporter/HtmlCoverageReporter.php";
// Initializations
$includePaths = array();
$excludePaths = array();
if (!$OPTION['cov-url']){
if(!$OPTION['report'] && !$OPTION['cov-data-files']) {
echo "ERROR: No --cov-url option specified.\n";
exit(1);
}
}
if($OPTION['init']) {
if(!$OPTION['tmp-dir']) {
$OPTION['tmp-dir'] = $util->getTmpDir();
}
if(!$OPTION['cov-file-name']) {
$OPTION['cov-file-name'] = "phpcoverage.data.xml";
}
}
if($OPTION['report']) {
if (!$OPTION['report-name']){
echo "ERROR: No --report-name option specified.\n";
exit(1);
}
if(!$OPTION['report-dir']) {
if(!empty($PHPCOVERAGE_REPORT_DIR)) {
$OPTION["report-dir"] = $PHPCOVERAGE_REPORT_DIR;
}
else {
$OPTION["report-dir"] = "report";
}
}
if(empty($OPTION['appbase-path']) && !empty($PHPCOVERAGE_APPBASE_PATH)) {
$OPTION['appbase-path'] = realpath($PHPCOVERAGE_APPBASE_PATH);
}
if(isset($OPTION['include-paths'])) {
$includePaths = explode(",", $OPTION['include-paths']);
}
if(isset($OPTION['appbase-path']) && !empty($OPTION["appbase-path"])) {
$includePaths[] = $OPTION['appbase-path'];
}
if(isset($OPTION['exclude-paths'])) {
$excludePaths = explode(",", $OPTION['exclude-paths']);
}
if($OPTION['local']) {
//local coverage run
if(empty($OPTION['test-driver'])) {
echo "Error: No test driver file specified.\n";
exit(1);
}
if(!is_file($OPTION['test-driver'])) {
echo "Error: No such file: " . $OPTION['test-driver'] . "\n";
exit(1);
}
$excludePaths[] = $OPTION['test-driver'];
}
}
if ($OPTION['verbose']){
echo "Options: " . print_r($OPTION, true) . "\n";
echo "include-paths: " . print_r($includePaths, true) . "\n";
echo "exclude-paths: " . print_r($excludePaths, true) . "\n";
}
//
//
//
if ($OPTION['init']){
echo "PHPCoverage: init " . $OPTION['cov-url'] . "?phpcoverage-action=init&cov-file-name=". urlencode($OPTION["cov-file-name"]) . "&tmp-dir=" . urlencode($OPTION['tmp-dir']) . "\n";
//
// Initialize the PHPCoverage reporting framework
//
file_get_contents($OPTION['cov-url'] . "?phpcoverage-action=init&cov-file-name=". urlencode($OPTION["cov-file-name"]) . "&tmp-dir=" . urlencode($OPTION['tmp-dir']));
}
else if ($OPTION['report']){
if(empty($OPTION['local'])) {
//
// Retrieve coverage data (xml) from the PHPCoverage reporting framework
//
if($OPTION['cov-data-files']) {
$OPTION['cov-data-fileset'] = explode(",", $OPTION['cov-data-files']);
foreach($OPTION['cov-data-fileset'] as $covDataFile) {
if(!is_readable($covDataFile)) {
echo "Error: Cannot read cov-data-file: " . $covDataFile . "\n";
exit(1);
}
$xmlUrl[] = $covDataFile;
}
}
else {
echo "PHPCoverage: report " . $OPTION['cov-url'] . "?phpcoverage-action=get-coverage-xml" . "\n";
$xmlUrl = $OPTION['cov-url'] . "?phpcoverage-action=get-coverage-xml";
}
//
// Configure reporter, and generate the PHPCoverage report
//
$covReporter = new HtmlCoverageReporter($OPTION['report-name'], "", $OPTION["report-dir"]);
//
// Notice the coverage recorder is of type RemoteCoverageRecorder
//
$cov = new RemoteCoverageRecorder($includePaths, $excludePaths, $covReporter);
$cov->generateReport($xmlUrl, true);
$covReporter->printTextSummary($OPTION["report-dir"] . "/report.txt");
// Should the summary be printed to console ?
if(isset($OPTION['print-summary']) && $OPTION['print-summary']) {
$covReporter->printTextSummary();
}
}
else {
//
// Configure reporter, and generate the PHPCoverage report
//
$covReporter = new HtmlCoverageReporter($OPTION['report-name'], "", $OPTION["report-dir"]);
$cov = new CoverageRecorder($includePaths, $excludePaths, $covReporter);
$cov->startInstrumentation();
echo "\n>>>>>>>>>>>>>>>>>>> Output from the test driver begins\n\n";
include $OPTION['test-driver'];
echo "\n\nOutput from the test driver ends <<<<<<<<<<<<<<<<<<<<<\n";
$cov->stopInstrumentation();
$cov->generateReport();
$covReporter->printTextSummary($OPTION["report-dir"] . "/report.txt");
// Should the summary be printed to console ?
if(isset($OPTION['print-summary']) && $OPTION['print-summary']) {
$covReporter->printTextSummary();
}
}
}
else if ($OPTION['cleanup']){
echo "PHPCoverage: cleanup " . $OPTION['cov-url'] . "?phpcoverage-action=cleanup";
file_get_contents($OPTION['cov-url'] . "?phpcoverage-action=cleanup");
}
?>
+305
View File
@@ -0,0 +1,305 @@
<?php
/*
* $Id$
*
* Copyright(c) 2004-2006, SpikeSource Inc. All Rights Reserved.
* Licensed under the Open Software License version 2.1
* (See http://www.spikesource.com/license.html)
*/
?>
<?php
#!/bin/php
if(!defined("__PHPCOVERAGE_HOME")) {
define("__PHPCOVERAGE_HOME", dirname(dirname(__FILE__)));
}
require_once __PHPCOVERAGE_HOME . "/conf/phpcoverage.conf.php";
require_once __PHPCOVERAGE_HOME . "/util/Utility.php";
## Instruments the PHP Source files
/**
* Print help message and exit
*
* @access public
*/
function help() {
echo "Usage: " . basename(__FILE__) . " -b <application-base-path> [-p <phpcoverage-home>] [-r] [-u] [-e <exclude-file-list>]"
. "[-v] [-h] [path1 [path2 [...]]]\n";
echo "\n";
echo " Options: \n";
echo " -b <application-base-path> Application directory accessible via HTTP "
. "where PHPCoverage files should be copied.\n";
echo " -p <phpcoverage-home> Path to PHPCoverage Home.\n";
echo " -r Recursively instrument PHP files.\n";
echo " -u Undo instrumentation.\n";
echo " -e <file1,file2,...> Execlude files in the file list.\n";
echo " -v Be verbose.\n";
echo " -h Print this help and exit.\n";
echo "\n";
exit(0);
}
/**
* Print error message and exit
*
* @param $msg Message to write to console.
* @access public
*/
function error($msg) {
echo basename(__FILE__) . ": [ERROR] " . $msg . "\n";
exit(1);
}
/**
* Write a information message
*
* @param $msg Message to write to console.
* @access public
*/
function writeMsg($msg) {
global $VERBOSE;
if($VERBOSE) {
echo basename(__FILE__) . ": [INFO] " . $msg . "\n";
}
}
/**
* Instrument the PHP file.
*
* @param $file File path
* @access public
*/
function instrument($file) {
global $LOCAL_PHPCOVERAGE_LOCATION, $top, $bottom;
$tmpfile = "$file.tmp";
$contents = file_get_contents($file);
$len = strlen($contents);
if(strpos($contents, $top) === 0 && strrpos($contents, $bottom) === ($len - strlen($bottom))) {
writeMsg("Skipping $file.");
return;
}
$fp = fopen($tmpfile, "w");
if(!$fp) {
error("Cannot write to file: $tmpfile");
}
fputs($fp, $top);
fwrite($fp, $contents);
fputs($fp, $bottom);
fclose($fp);
// Delete if already exists - 'rename()' on Windows will return false otherwise
if(file_exists($file)) {
unlink($file);
}
$ret = rename($tmpfile, $file);
if(!$ret) {
error("Cannot save file: $file");
}
writeMsg("Instrumented: $file.");
}
/**
* Uninstrument the PHP file
*
* @param $file File path
* @access public
*/
function uninstrument($file) {
global $LOCAL_PHPCOVERAGE_LOCATION, $top, $bottom;
$tmpfile = "$file.tmp";
$contents = file_get_contents($file);
$len = strlen($contents);
if(strpos($contents, $top) !== 0 && strrpos($contents, $bottom) !== ($len - strlen($bottom))) {
writeMsg("Skipping $file.");
return;
}
$fr = fopen($file, "r");
$fw = fopen($tmpfile, "w");
if(!$fr) {
error("Cannot read file: $file");
}
if(!$fr) {
error("Cannot write to file: $tmpfile");
}
while(!feof($fr)) {
$line = fgets($fr);
if(strpos($line, $top) === false && strpos($line, $bottom) === false) {
fputs($fw, $line);
}
}
fclose($fr);
fclose($fw);
// Delete if already exists - 'rename()' on Windows will return false otherwise
if(file_exists($file)) {
unlink($file);
}
$ret = rename($tmpfile, $file);
if(!$ret) {
error("Cannot save file: $file");
}
writeMsg("Uninstrumented: $file");
}
/**
* Retrive a list of all PHP files in the given directory
*
* @param $dir Directory to scan
* @param $recursive True is directory is scanned recursively
* @return Array List of PHP files
* @access public
*/
function get_all_php_files($dir, &$excludeFiles, $recursive) {
global $spc_config;
$phpExtensions = $spc_config["extensions"];
$dirs[] = $dir;
while(count($dirs) > 0) {
$currDir = realpath(array_pop($dirs));
if(!is_readable($currDir)) {
continue;
}
$currFiles = scandir($currDir);
for($j = 0; $j < count($currFiles); $j++) {
if($currFiles[$j] == "." || $currFiles[$j] == "..") {
continue;
}
$currFiles[$j] = $currDir . "/" . $currFiles[$j];
if(is_file($currFiles[$j])) {
$pathParts = pathinfo($currFiles[$j]);
// Ignore phpcoverage bottom and top stubs
if(strpos($pathParts['basename'], "phpcoverage.remote.") !== false) {
continue;
}
// Ignore files specified in the exclude list
if(in_array(realpath($currFiles[$j]), $excludeFiles) !== false) {
continue;
}
if(isset($pathParts['extension'])
&& in_array($pathParts['extension'], $phpExtensions)) {
$files[] = $currFiles[$j];
}
}
else if(is_dir($currFiles[$j]) && $recursive) {
$dirs[] = $currFiles[$j];
}
}
}
return $files;
}
// Initialize
$RECURSIVE = false;
$UNDO = false;
$top_file = "/phpcoverage.remote.top.inc.php";
$bottom_file = "/phpcoverage.remote.bottom.inc.php";
//print_r($argv);
for($i = 1; $i < $argc; $i++) {
switch($argv[$i]) {
case "-r":
$RECURSIVE = true;
break;
case "-p":
$PHPCOVERAGE_HOME = $argv[++$i];
break;
case "-b":
$LOCAL_PHPCOVERAGE_LOCATION = $argv[++$i];
break;
case "-u":
$UNDO = true;
break;
case "-e":
$EXCLUDE_FILES = explode(",", $argv[++$i]);
break;
case "-v":
$VERBOSE = true;
break;
case "-h":
help();
break;
default:
$paths[] = $argv[$i];
break;
}
}
if(!is_dir($LOCAL_PHPCOVERAGE_LOCATION)) {
error("LOCAL_PHPCOVERAGE_LOCATION [$LOCAL_PHPCOVERAGE_LOCATION] not found.");
}
if(empty($PHPCOVERAGE_HOME) || !is_dir($PHPCOVERAGE_HOME)) {
$PHPCOVERAGE_HOME = __PHPCOVERAGE_HOME;
if(empty($PHPCOVERAGE_HOME) || !is_dir($PHPCOVERAGE_HOME)) {
error("PHPCOVERAGE_HOME does not exist. [" . $PHPCOVERAGE_HOME . "]");
}
}
$LOCAL_PHPCOVERAGE_LOCATION = realpath($LOCAL_PHPCOVERAGE_LOCATION);
if(file_exists($LOCAL_PHPCOVERAGE_LOCATION . $top_file)) {
unlink($LOCAL_PHPCOVERAGE_LOCATION . $top_file);
}
$ret = copy($PHPCOVERAGE_HOME . $top_file, $LOCAL_PHPCOVERAGE_LOCATION . $top_file);
if(!$ret) {
error("Cannot copy to $LOCAL_PHPCOVERAGE_LOCATION");
}
if(file_exists($LOCAL_PHPCOVERAGE_LOCATION . $bottom_file)) {
unlink($LOCAL_PHPCOVERAGE_LOCATION . $bottom_file);
}
$ret = copy($PHPCOVERAGE_HOME . $bottom_file, $LOCAL_PHPCOVERAGE_LOCATION . $bottom_file);
if(!$ret) {
error("Cannot copy to $LOCAL_PHPCOVERAGE_LOCATION");
}
$top="<?php require_once \"" . $LOCAL_PHPCOVERAGE_LOCATION . $top_file ."\"; ?>\n";
$bottom="<?php require \"" . $LOCAL_PHPCOVERAGE_LOCATION . $bottom_file . "\"; ?>\n";
if(empty($paths)) {
$paths[] = getcwd();
}
if(!isset($EXCLUDE_FILES) || empty($EXCLUDE_FILES)) {
$EXCLUDE_FILES = array();
}
for($i = 0; $i < count($EXCLUDE_FILES); $i++) {
// Remove a file from the array if it does not exist
if(!file_exists($EXCLUDE_FILES[$i])) {
array_splice($EXCLUDE_FILES, $i, 1);
$i --;
continue;
}
$EXCLUDE_FILES[$i] = realpath($EXCLUDE_FILES[$i]);
}
//print_r($paths);
foreach($paths as $path) {
unset($files);
if(is_dir($path)) {
$files = get_all_php_files($path, $EXCLUDE_FILES, $RECURSIVE);
}
else if(is_file($path)) {
$files[] = $path;
}
else {
error("Unknown entity: $path");
}
//print_r($files);
foreach($files as $file) {
if($UNDO) {
uninstrument($file);
}
else {
instrument($file);
}
}
}
?>