adding coverage extension for simpletest
This commit is contained in:
parent
bae07faa34
commit
27eb665516
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
/**
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
/**
|
||||
* Include this in any file to start coverage, coverage will automatically end
|
||||
* when process dies.
|
||||
*/
|
||||
require_once(dirname(__FILE__) .'/coverage.php');
|
||||
|
||||
if (CodeCoverage::isCoverageOn()) {
|
||||
$coverage = CodeCoverage::getInstance();
|
||||
$coverage->startCoverage();
|
||||
register_shutdown_function("stop_coverage");
|
||||
}
|
||||
|
||||
function stop_coverage() {
|
||||
# hack until i can think of a way to run tests first and w/o exiting
|
||||
$autorun = function_exists("run_local_tests");
|
||||
if ($autorun) {
|
||||
$result = run_local_tests();
|
||||
}
|
||||
CodeCoverage::getInstance()->stopCoverage();
|
||||
if ($autorun) {
|
||||
exit($result ? 0 : 1);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* Close code coverage data collection, next step is to generate report
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
/**
|
||||
* include coverage files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/../coverage.php');
|
||||
$cc = CodeCoverage::getInstance();
|
||||
$cc->readSettings();
|
||||
$cc->writeUntouched();
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* Initialize code coverage data collection, next step is to run your tests
|
||||
* with ini setting auto_prepend_file=autocoverage.php ...
|
||||
*
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
# optional arguments:
|
||||
# --include=<some filepath regexp> these files should be included coverage report
|
||||
# --exclude=<come filepath regexp> these files should not be included in coverage report
|
||||
# --maxdepth=2 when considering which file were not touched, scan directories
|
||||
#
|
||||
# Example:
|
||||
# php-coverage-open.php --include='.*\.php$' --include='.*\.inc$' --exclude='.*/tests/.*'
|
||||
/**#@+
|
||||
* include coverage files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/../coverage_utils.php');
|
||||
CoverageUtils::requireSqlite();
|
||||
require_once(dirname(__FILE__) . '/../coverage.php');
|
||||
/**#@-*/
|
||||
$cc = new CodeCoverage();
|
||||
$cc->log = 'coverage.sqlite';
|
||||
$args = CoverageUtils::parseArguments($_SERVER['argv'], TRUE);
|
||||
$cc->includes = CoverageUtils::issetOr($args['include[]'], array('.*\.php$'));
|
||||
$cc->excludes = CoverageUtils::issetOr($args['exclude[]']);
|
||||
$cc->maxDirectoryDepth = (int)CoverageUtils::issetOr($args['maxdepth'], '1');
|
||||
$cc->resetLog();
|
||||
$cc->writeSettings();
|
||||
?>
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
/**
|
||||
* Generate a code coverage report
|
||||
*
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
# optional arguments:
|
||||
# --reportDir=some/directory the default is ./coverage-report
|
||||
# --title='My Coverage Report' title the main page of your report
|
||||
|
||||
/**#@+
|
||||
* include coverage files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/../coverage_utils.php');
|
||||
require_once(dirname(__FILE__) . '/../coverage.php');
|
||||
require_once(dirname(__FILE__) . '/../coverage_reporter.php');
|
||||
/**#@-*/
|
||||
$cc = CodeCoverage::getInstance();
|
||||
$cc->readSettings();
|
||||
$handler = new CoverageDataHandler($cc->log);
|
||||
$report = new CoverageReporter();
|
||||
$args = CoverageUtils::parseArguments($_SERVER['argv']);
|
||||
$report->reportDir = CoverageUtils::issetOr($args['reportDir'], 'coverage-report');
|
||||
$report->title = CoverageUtils::issetOr($args['title'], "Simpletest Coverage");
|
||||
$report->coverage = $handler->read();
|
||||
$report->untouched = $handler->readUntouchedFiles();
|
||||
$report->generate();
|
||||
?>
|
|
@ -0,0 +1,196 @@
|
|||
<?php
|
||||
/**
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
/**
|
||||
* load coverage data handle
|
||||
*/
|
||||
require_once dirname(__FILE__) . '/coverage_data_handler.php';
|
||||
|
||||
/**
|
||||
* Orchestrates code coverage both in this thread and in subthread under apache
|
||||
* Assumes this is running on same machine as apache.
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
class CodeCoverage {
|
||||
var $log;
|
||||
var $root;
|
||||
var $includes;
|
||||
var $excludes;
|
||||
var $directoryDepth;
|
||||
var $maxDirectoryDepth = 20; // reasonable, otherwise arbitrary
|
||||
var $title = "Code Coverage";
|
||||
|
||||
# NOTE: This assumes all code shares the same current working directory.
|
||||
var $settingsFile = './code-coverage-settings.dat';
|
||||
|
||||
static $instance;
|
||||
|
||||
function writeUntouched() {
|
||||
$touched = array_flip($this->getTouchedFiles());
|
||||
$untouched = array();
|
||||
$this->getUntouchedFiles($untouched, $touched, '.', '.');
|
||||
$this->includeUntouchedFiles($untouched);
|
||||
}
|
||||
|
||||
function &getTouchedFiles() {
|
||||
$handler = new CoverageDataHandler($this->log);
|
||||
$touched = $handler->getFilenames();
|
||||
return $touched;
|
||||
}
|
||||
|
||||
function includeUntouchedFiles($untouched) {
|
||||
$handler = new CoverageDataHandler($this->log);
|
||||
foreach ($untouched as $file) {
|
||||
$handler->writeUntouchedFile($file);
|
||||
}
|
||||
}
|
||||
|
||||
function getUntouchedFiles(&$untouched, $touched, $parentPath, $rootPath, $directoryDepth = 1) {
|
||||
$parent = opendir($parentPath);
|
||||
while ($file = readdir($parent)) {
|
||||
$path = "$parentPath/$file";
|
||||
if (is_dir($path)) {
|
||||
if ($file != '.' && $file != '..') {
|
||||
if ($this->isDirectoryIncluded($path, $directoryDepth)) {
|
||||
$this->getUntouchedFiles($untouched, $touched, $path, $rootPath, $directoryDepth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($this->isFileIncluded($path)) {
|
||||
$relativePath = CoverageDataHandler::ltrim($rootPath .'/', $path);
|
||||
if (!array_key_exists($relativePath, $touched)) {
|
||||
$untouched[] = $relativePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($parent);
|
||||
}
|
||||
|
||||
function resetLog() {
|
||||
error_log('reseting log');
|
||||
$new_file = fopen($this->log, "w");
|
||||
if (!$new_file) {
|
||||
throw new Exception("Could not create ". $this->log);
|
||||
}
|
||||
fclose($new_file);
|
||||
if (!chmod($this->log, 0666)) {
|
||||
throw new Exception("Could not change ownership on file ". $this->log);
|
||||
}
|
||||
$handler = new CoverageDataHandler($this->log);
|
||||
$handler->createSchema();
|
||||
}
|
||||
|
||||
function startCoverage() {
|
||||
$this->root = getcwd();
|
||||
if(!extension_loaded("xdebug")) {
|
||||
throw new Exception("Could not load xdebug extension");
|
||||
};
|
||||
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
|
||||
}
|
||||
|
||||
function stopCoverage() {
|
||||
$cov = xdebug_get_code_coverage();
|
||||
$this->filter($cov);
|
||||
$data = new CoverageDataHandler($this->log);
|
||||
chdir($this->root);
|
||||
$data->write($cov);
|
||||
unset($data); // release sqlite connection
|
||||
xdebug_stop_code_coverage();
|
||||
// make sure we wind up on same current working directory, otherwise
|
||||
// coverage handler writer doesn't know what directory to chop off
|
||||
chdir($this->root);
|
||||
}
|
||||
|
||||
function readSettings() {
|
||||
if (file_exists($this->settingsFile)) {
|
||||
$this->setSettings(file_get_contents($this->settingsFile));
|
||||
} else {
|
||||
error_log("could not find file ". $this->settingsFile);
|
||||
}
|
||||
}
|
||||
|
||||
function writeSettings() {
|
||||
file_put_contents($this->settingsFile, $this->getSettings());
|
||||
}
|
||||
|
||||
function getSettings() {
|
||||
$data = array(
|
||||
'log' => realpath($this->log),
|
||||
'includes' => $this->includes,
|
||||
'excludes' => $this->excludes);
|
||||
return serialize($data);
|
||||
}
|
||||
|
||||
function setSettings($settings) {
|
||||
$data = unserialize($settings);
|
||||
$this->log = $data['log'];
|
||||
$this->includes = $data['includes'];
|
||||
$this->excludes = $data['excludes'];
|
||||
}
|
||||
|
||||
function filter(&$coverage) {
|
||||
foreach ($coverage as $file => $line) {
|
||||
if (!$this->isFileIncluded($file)) {
|
||||
unset($coverage[$file]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isFileIncluded($file) {
|
||||
if (!empty($this->excludes)) {
|
||||
foreach ($this->excludes as $path) {
|
||||
if (preg_match('|' . $path . '|', $file)) {
|
||||
return False;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->includes)) {
|
||||
foreach ($this->includes as $path) {
|
||||
if (preg_match('|' . $path . '|', $file)) {
|
||||
return True;
|
||||
}
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
function isDirectoryIncluded($dir, $directoryDepth) {
|
||||
if ($directoryDepth >= $this->maxDirectoryDepth) {
|
||||
return false;
|
||||
}
|
||||
if (isset($this->excludes)) {
|
||||
foreach ($this->excludes as $path) {
|
||||
if (preg_match('|' . $path . '|', $dir)) {
|
||||
return False;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static function isCoverageOn() {
|
||||
$coverage = self::getInstance();
|
||||
$coverage->readSettings();
|
||||
if (empty($coverage->log) || !file_exists($coverage->log)) {
|
||||
trigger_error('No coverage log');
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
static function getInstance() {
|
||||
if (self::$instance == NULL) {
|
||||
self::$instance = new CodeCoverage();
|
||||
self::$instance->readSettings();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
/**
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
/**
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
class CoverageCalculator {
|
||||
|
||||
function coverageByFileVariables($file, $coverage) {
|
||||
$hnd = fopen($file, 'r');
|
||||
if ($hnd == null) {
|
||||
throw new Exception("File $file is missing");
|
||||
}
|
||||
$lines = array();
|
||||
for ($i = 1; !feof($hnd); $i++) {
|
||||
$line = fgets($hnd);
|
||||
$lineCoverage = $this->lineCoverageCodeToStyleClass($coverage, $i);
|
||||
$lines[$i] = array('lineCoverage' => $lineCoverage, 'code' => $line);
|
||||
}
|
||||
|
||||
fclose($hnd);
|
||||
|
||||
$var = compact('file', 'lines', 'coverage');
|
||||
return $var;
|
||||
}
|
||||
|
||||
function lineCoverageCodeToStyleClass($coverage, $line) {
|
||||
if (!array_key_exists($line, $coverage)) {
|
||||
return "comment";
|
||||
}
|
||||
$code = $coverage[$line];
|
||||
if (empty($code)) {
|
||||
return "comment";
|
||||
}
|
||||
switch ($code) {
|
||||
case -1:
|
||||
return "missed";
|
||||
case -2:
|
||||
return "dead";
|
||||
}
|
||||
|
||||
return "covered";
|
||||
}
|
||||
|
||||
function totalLoc($total, $coverage) {
|
||||
return $total + sizeof($coverage);
|
||||
}
|
||||
|
||||
function lineCoverage($total, $line) {
|
||||
# NOTE: counting dead code as covered, as it's almost always an executable line
|
||||
# strange artifact of xdebug or underlying system
|
||||
return $total + ($line > 0 || $line == -2 ? 1 : 0);
|
||||
}
|
||||
|
||||
function totalCoverage($total, $coverage) {
|
||||
return $total + array_reduce($coverage, array(&$this, "lineCoverage"));
|
||||
}
|
||||
|
||||
static function reportFilename($filename) {
|
||||
return preg_replace('|[/\\\\]|', '_', $filename) . '.html';
|
||||
}
|
||||
|
||||
function percentCoverageByFile($coverage, $file, &$results) {
|
||||
$byFileReport = self::reportFilename($file);
|
||||
|
||||
$loc = sizeof($coverage);
|
||||
if ($loc == 0)
|
||||
return 0;
|
||||
$lineCoverage = array_reduce($coverage, array(&$this, "lineCoverage"));
|
||||
$percentage = 100 * ($lineCoverage / $loc);
|
||||
$results[0][$file] = array('byFileReport' => $byFileReport, 'percentage' => $percentage);
|
||||
}
|
||||
|
||||
function variables($coverage, $untouched) {
|
||||
$coverageByFile = array();
|
||||
array_walk($coverage, array(&$this, "percentCoverageByFile"), array(&$coverageByFile));
|
||||
|
||||
$totalLoc = array_reduce($coverage, array(&$this, "totalLoc"));
|
||||
|
||||
if ($totalLoc > 0) {
|
||||
$totalLinesOfCoverage = array_reduce($coverage, array(&$this, "totalCoverage"));
|
||||
$totalPercentCoverage = 100 * ($totalLinesOfCoverage / $totalLoc);
|
||||
}
|
||||
|
||||
$untouchedPercentageDenominator = sizeof($coverage) + sizeof($untouched);
|
||||
if ($untouchedPercentageDenominator > 0) {
|
||||
$filesTouchedPercentage = 100 * sizeof($coverage) / $untouchedPercentageDenominator;
|
||||
}
|
||||
|
||||
$var = compact('coverageByFile', 'totalPercentCoverage', 'totalLoc', 'totalLinesOfCoverage', 'filesTouchedPercentage');
|
||||
$var['untouched'] = $untouched;
|
||||
return $var;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
/**
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
/**
|
||||
* @todo which db abstraction layer is this?
|
||||
*/
|
||||
require_once 'DB/sqlite.php';
|
||||
|
||||
/**
|
||||
* Persists code coverage data into SQLite database and aggregate data for convienent
|
||||
* interpretation in report generator. Be sure to not to keep an instance longer
|
||||
* than you have, otherwise you risk overwriting database edits from another process
|
||||
* also trying to make updates.
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
class CoverageDataHandler {
|
||||
|
||||
var $db;
|
||||
|
||||
function __construct($filename) {
|
||||
$this->filename = $filename;
|
||||
$this->db = new SQLiteDatabase($filename);
|
||||
if (empty($this->db)) {
|
||||
throw new Exception("Could not create sqlite db ". $filename);
|
||||
}
|
||||
}
|
||||
|
||||
function createSchema() {
|
||||
$this->db->queryExec("create table untouched (filename text)");
|
||||
$this->db->queryExec("create table coverage (name text, coverage text)");
|
||||
}
|
||||
|
||||
function &getFilenames() {
|
||||
$filenames = array();
|
||||
$cursor = $this->db->unbufferedQuery("select distinct name from coverage");
|
||||
while ($row = $cursor->fetch()) {
|
||||
$filenames[] = $row[0];
|
||||
}
|
||||
|
||||
return $filenames;
|
||||
}
|
||||
|
||||
function write($coverage) {
|
||||
foreach ($coverage as $file => $lines) {
|
||||
$coverageStr = serialize($lines);
|
||||
$relativeFilename = self::ltrim(getcwd() . '/', $file);
|
||||
$sql = "insert into coverage (name, coverage) values ('$relativeFilename', '$coverageStr')";
|
||||
# if this fails, check you have write permission
|
||||
$this->db->queryExec($sql);
|
||||
}
|
||||
}
|
||||
|
||||
function read() {
|
||||
$coverage = array_flip($this->getFilenames());
|
||||
foreach($coverage as $file => $garbage) {
|
||||
$coverage[$file] = $this->readFile($file);
|
||||
}
|
||||
return $coverage;
|
||||
}
|
||||
|
||||
function &readFile($file) {
|
||||
$sql = "select coverage from coverage where name = '$file'";
|
||||
$aggregate = array();
|
||||
$result = $this->db->query($sql);
|
||||
while ($result->valid()) {
|
||||
$row = $result->current();
|
||||
$this->aggregateCoverage($aggregate, unserialize($row[0]));
|
||||
$result->next();
|
||||
}
|
||||
|
||||
return $aggregate;
|
||||
}
|
||||
|
||||
function aggregateCoverage(&$total, $next) {
|
||||
foreach ($next as $lineno => $code) {
|
||||
if (!isset($total[$lineno])) {
|
||||
$total[$lineno] = $code;
|
||||
} else {
|
||||
$total[$lineno] = $this->aggregateCoverageCode($total[$lineno], $code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function aggregateCoverageCode($code1, $code2) {
|
||||
switch($code1) {
|
||||
case -2: return -2;
|
||||
case -1: return $code2;
|
||||
default:
|
||||
switch ($code2) {
|
||||
case -2: return -2;
|
||||
case -1: return $code1;
|
||||
}
|
||||
}
|
||||
return $code1 + $code2;
|
||||
}
|
||||
|
||||
static function ltrim($cruft, $pristine) {
|
||||
if(stripos($pristine, $cruft) === 0) {
|
||||
return substr($pristine, strlen($cruft));
|
||||
}
|
||||
return $pristine;
|
||||
}
|
||||
|
||||
function writeUntouchedFile($file) {
|
||||
$relativeFile = CoverageDataHandler::ltrim('./', $file);
|
||||
$sql = "insert into untouched values ('$relativeFile')";
|
||||
$this->db->queryExec($sql);
|
||||
}
|
||||
|
||||
function &readUntouchedFiles() {
|
||||
$untouched = array();
|
||||
$result = $this->db->query("select filename from untouched order by filename");
|
||||
while ($result->valid()) {
|
||||
$row = $result->current();
|
||||
$untouched[] = $row[0];
|
||||
$result->next();
|
||||
}
|
||||
|
||||
return $untouched;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
/**
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
/**#@+
|
||||
* include additional coverage files
|
||||
*/
|
||||
require_once dirname(__FILE__) .'/coverage_calculator.php';
|
||||
require_once dirname(__FILE__) .'/coverage_utils.php';
|
||||
require_once dirname(__FILE__) .'/simple_coverage_writer.php';
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Take aggregated coverage data and generate reports from it using smarty
|
||||
* templates
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
class CoverageReporter {
|
||||
var $coverage;
|
||||
var $untouched;
|
||||
var $reportDir;
|
||||
var $title = 'Coverage';
|
||||
var $writer;
|
||||
var $calculator;
|
||||
|
||||
function __construct() {
|
||||
$this->writer = new SimpleCoverageWriter();
|
||||
$this->calculator = new CoverageCalculator();
|
||||
}
|
||||
|
||||
function generateSummaryReport($out) {
|
||||
$variables = $this->calculator->variables($this->coverage, $this->untouched);
|
||||
$variables['title'] = $this->title;
|
||||
$report = $this->writer->writeSummary($out, $variables);
|
||||
fwrite($out, $report);
|
||||
}
|
||||
|
||||
function generate() {
|
||||
CoverageUtils::mkdir($this->reportDir);
|
||||
|
||||
$index = $this->reportDir .'/index.html';
|
||||
$hnd = fopen($index, 'w');
|
||||
$this->generateSummaryReport($hnd);
|
||||
fclose($hnd);
|
||||
|
||||
foreach ($this->coverage as $file => $cov) {
|
||||
$byFile = $this->reportDir .'/'. self::reportFilename($file);
|
||||
$byFileHnd = fopen($byFile, 'w');
|
||||
$this->generateCoverageByFile($byFileHnd, $file, $cov);
|
||||
fclose($byFileHnd);
|
||||
}
|
||||
|
||||
echo "generated report $index\n";
|
||||
}
|
||||
|
||||
function generateCoverageByFile($out, $file, $cov) {
|
||||
$variables = $this->calculator->coverageByFileVariables($file, $cov);
|
||||
$variables['title'] = $this->title .' - '. $file;
|
||||
$this->writer->writeByFile($out, $variables);
|
||||
}
|
||||
|
||||
static function reportFilename($filename) {
|
||||
return preg_replace('|[/\\\\]|', '_', $filename) . '.html';
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
/**
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
/**
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
class CoverageUtils {
|
||||
|
||||
static function mkdir($dir) {
|
||||
if (!file_exists($dir)) {
|
||||
mkdir($dir, 0777, True);
|
||||
} else {
|
||||
if (!is_dir($dir)) {
|
||||
throw new Exception($dir .' exists as a file, not a directory');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function requireSqlite() {
|
||||
if (!self::isPackageClassAvailable('DB/sqlite.php', 'SQLiteDatabase')) {
|
||||
echo "sqlite library is required to be installed and available in include_path";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static function isPackageClassAvailable($includeFile, $class) {
|
||||
@include_once($includeFile);
|
||||
return class_exists($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses simple parameters from CLI.
|
||||
*
|
||||
* Puts trailing parameters into string array in 'extraArguments'
|
||||
*
|
||||
* Example:
|
||||
* $args = CoverageUtil::parseArguments($_SERVER['argv']);
|
||||
* if ($args['verbose']) echo "Verbose Mode On\n";
|
||||
* $files = $args['extraArguments'];
|
||||
*
|
||||
* Example CLI:
|
||||
* --foo=blah -x -h some trailing arguments
|
||||
*
|
||||
* if multiValueMode is true
|
||||
* Example CLI:
|
||||
* --include=a --include=b --exclude=c
|
||||
* Then
|
||||
* $args = CoverageUtil::parseArguments($_SERVER['argv']);
|
||||
* $args['include[]'] will equal array('a', 'b')
|
||||
* $args['exclude[]'] will equal array('c')
|
||||
* $args['exclude'] will equal c
|
||||
* $args['include'] will equal b NOTE: only keeps last value
|
||||
*
|
||||
* @param unknown_type $argv
|
||||
* @param supportMutliValue - will store 2nd copy of value in an array with key "foo[]"
|
||||
* @return unknown
|
||||
*/
|
||||
static public function parseArguments($argv, $mutliValueMode = False) {
|
||||
$args = array();
|
||||
$args['extraArguments'] = array();
|
||||
array_shift($argv); // scriptname
|
||||
foreach ($argv as $arg) {
|
||||
if (ereg('^--([^=]+)=(.*)', $arg, $reg)) {
|
||||
$args[$reg[1]] = $reg[2];
|
||||
if ($mutliValueMode) {
|
||||
self::addItemAsArray($args, $reg[1], $reg[2]);
|
||||
}
|
||||
} elseif (ereg('^[-]{1,2}([^[:blank:]]+)', $arg, $reg)) {
|
||||
$nonnull = '';
|
||||
$args[$reg[1]] = $nonnull;
|
||||
if ($mutliValueMode) {
|
||||
self::addItemAsArray($args, $reg[1], $nonnull);
|
||||
}
|
||||
} else {
|
||||
$args['extraArguments'][] = $arg;
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value as an array of one, or appends to an existing array elements
|
||||
*
|
||||
* @param unknown_type $array
|
||||
* @param unknown_type $item
|
||||
*/
|
||||
static function addItemAsArray(&$array, $key, $item) {
|
||||
$array_key = $key .'[]';
|
||||
if (array_key_exists($array_key, $array)) {
|
||||
$array[$array_key][] = $item;
|
||||
} else {
|
||||
$array[$array_key] = array($item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* isset function with default value
|
||||
*
|
||||
* Example: $z = CoverageUtils::issetOr($array[$key], 'no value given')
|
||||
*
|
||||
* @param unknown_type $val
|
||||
* @param unknown_type $default
|
||||
* @return first value unless value is not set then returns 2nd arg or null if no 2nd arg
|
||||
*/
|
||||
static public function issetOr(&$val, $default = null)
|
||||
{
|
||||
return isset($val) ? $val : $default;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
/**
|
||||
* @package SimpleTest
|
||||
* @subpackage Extensions
|
||||
*/
|
||||
interface CoverageWriter {
|
||||
|
||||
function writeSummary($out, $variables);
|
||||
|
||||
function writeByFile($out, $variables);
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* SimpleCoverageWriter class file
|
||||
* @package SimpleTest
|
||||
* @subpackage UnitTester
|
||||
* @version $Id: unit_tester.php 1882 2009-07-01 14:30:05Z lastcraft $
|
||||
*/
|
||||
/**
|
||||
* base coverage writer class
|
||||
*/
|
||||
require_once dirname(__FILE__) .'/coverage_writer.php';
|
||||
|
||||
/**
|
||||
* SimpleCoverageWriter class
|
||||
* @package SimpleTest
|
||||
* @subpackage UnitTester
|
||||
*/
|
||||
class SimpleCoverageWriter implements CoverageWriter {
|
||||
|
||||
function writeSummary($out, $variables) {
|
||||
extract($variables);
|
||||
$now = date("F j, Y, g:i a");
|
||||
ob_start();
|
||||
include dirname(__FILE__) . '/templates/index.php';
|
||||
$contents = ob_get_contents();
|
||||
fwrite ($out, $contents);
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
function writeByFile($out, $variables) {
|
||||
extract($variables);
|
||||
ob_start();
|
||||
include dirname(__FILE__) . '/templates/file.php';
|
||||
$contents = ob_get_contents();
|
||||
fwrite ($out, $contents);
|
||||
ob_end_clean();
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,60 @@
|
|||
<html>
|
||||
<head>
|
||||
<title><?php echo $title ?></title>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: "Gill Sans MT", "Gill Sans", GillSans, Arial, Helvetica, sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: medium;
|
||||
}
|
||||
#code {
|
||||
border-spacing: 0;
|
||||
}
|
||||
.lineNo {
|
||||
color: #ccc;
|
||||
}
|
||||
.code, .lineNo {
|
||||
white-space: pre;
|
||||
font-family: monospace;
|
||||
}
|
||||
.covered {
|
||||
color: #090;
|
||||
}
|
||||
.missed {
|
||||
color: #f00;
|
||||
}
|
||||
.dead {
|
||||
color: #00f;
|
||||
}
|
||||
.comment {
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h1 id="title"><?php echo $title ?></h1>
|
||||
<table id="code">
|
||||
<tbody>
|
||||
<?php foreach ($lines as $lineNo => $line) { ?>
|
||||
<tr>
|
||||
<td><span class="lineNo"><?php echo $lineNo ?></span></td>
|
||||
<td><span class="<?php echo $line['lineCoverage'] ?> code"><?php echo htmlentities($line['code']) ?></span></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Legend</h2>
|
||||
<dl>
|
||||
<dt><span class="missed">Missed</span></dt>
|
||||
<dd>lines code that <strong>were not</strong> excersized during program execution.</dd>
|
||||
<dt><span class="covered">Covered</span></dt>
|
||||
<dd>lines code <strong>were</strong> excersized during program execution.</dd>
|
||||
<dt><span class="comment">Comment/non executable</span></dt>
|
||||
<dd>Comment or non-executable line of code.</dd>
|
||||
<dt><span class="dead">Dead</span></dt>
|
||||
<dd>lines of code that according to xdebug could not be executed. This is counted as coverage code because
|
||||
in almost all cases it is code that runnable.</dd>
|
||||
</dl>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,106 @@
|
|||
<html>
|
||||
<head>
|
||||
<title><?php echo $title ?></title>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
h1 {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Gill Sans MT", "Gill Sans", GillSans, Arial, Helvetica,
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
td.percentage {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
caption {
|
||||
border-bottom: thin solid;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 1em;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h1 id="title"><?php echo $title ?></h1>
|
||||
<table>
|
||||
<caption>Summary</caption>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Total Coverage (<a href="#total-coverage">?</a>) :</td>
|
||||
<td class="percentage"><span class="totalPercentCoverage"><?php echo number_format($totalPercentCoverage, 0) ?>%</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Files Covered (<a href="#total-files-covered">?</a>) :</td>
|
||||
<td class="percentage"><span class="filesTouchedPercentage"><?php echo number_format($filesTouchedPercentage, 0) ?>%</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Report Generation Date :</td>
|
||||
<td><?php echo $now ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table id="covered-files">
|
||||
<caption>Coverage (<a href="#coverage">?</a>)</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>File</th>
|
||||
<th>Coverage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($coverageByFile as $file => $coverage) { ?>
|
||||
<tr>
|
||||
<td><a class="byFileReportLink" href="<?php echo $coverage['byFileReport'] ?>"><?php echo $file ?></a></td>
|
||||
<td class="percentage"><span class="percentCoverage"><?php echo number_format($coverage['percentage'], 0) ?>%</span></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<caption>Files Not Covered (<a href="#untouched">?</a>)</caption>
|
||||
<tbody>
|
||||
<?php foreach ($untouched as $key => $file) { ?>
|
||||
<tr>
|
||||
<td><span class="untouchedFile"><?php echo $file ?></span></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>Glossary</h2>
|
||||
<dl>
|
||||
<dt><a name="total-coverage">Total Coverage</a></dt>
|
||||
<dd>Ratio of all the lines of executable code that were executed to the
|
||||
lines of code that were not executed. This does not include the files
|
||||
that were not covered at all.</dd>
|
||||
<dt><a name="total-files-covered">Total Files Covered</a></dt>
|
||||
<dd>This is the ratio of the number of files tested, to the number of
|
||||
files not tested at all.</dd>
|
||||
<dt><a name="coverage">Coverage</a></dt>
|
||||
<dd>These files were parsed and loaded by the php interpreter while
|
||||
running the tests. Percentage is determined by the ratio of number of
|
||||
lines of code executed to the number of possible executable lines of
|
||||
code. "dead" lines of code, or code that could not be executed
|
||||
according to xdebug, are counted as covered because in almost all cases
|
||||
it is the end of a logical loop.</dd>
|
||||
<dt><a name="untouched">Files Not Covered</a></dt>
|
||||
<dd>These files were not loaded by the php interpreter at anytime
|
||||
during a unit test. You could consider these files having 0% coverage,
|
||||
but because it is difficult to determine the total coverage unless you
|
||||
could count the lines for executable code, this is not reflected in the
|
||||
Total Coverage calculation.</dd>
|
||||
</dl>
|
||||
|
||||
<p>Code coverage generated by <a href="http://www.simpletest.org">SimpleTest</a></p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
require_once(dirname(__FILE__) . '/../../../autorun.php');
|
||||
|
||||
class CoverageCalculatorTest extends UnitTestCase {
|
||||
function skip() {
|
||||
$this->skipIf(
|
||||
!file_exists('DB/sqlite.php'),
|
||||
'The Coverage extension needs to have PEAR installed');
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
require_once dirname(__FILE__) .'/../coverage_calculator.php';
|
||||
$this->calc = new CoverageCalculator();
|
||||
}
|
||||
|
||||
function testVariables() {
|
||||
$coverage = array('file' => array(1,1,1,1));
|
||||
$untouched = array('missed-file');
|
||||
$variables = $this->calc->variables($coverage, $untouched);
|
||||
$this->assertEqual(4, $variables['totalLoc']);
|
||||
$this->assertEqual(100, $variables['totalPercentCoverage']);
|
||||
$this->assertEqual(4, $variables['totalLinesOfCoverage']);
|
||||
$expected = array('file' => array('byFileReport' => 'file.html', 'percentage' => 100));
|
||||
$this->assertEqual($expected, $variables['coverageByFile']);
|
||||
$this->assertEqual(50, $variables['filesTouchedPercentage']);
|
||||
$this->assertEqual($untouched, $variables['untouched']);
|
||||
}
|
||||
|
||||
function testPercentageCoverageByFile() {
|
||||
$coverage = array(0,0,0,1,1,1);
|
||||
$results = array();
|
||||
$this->calc->percentCoverageByFile($coverage, 'file', $results);
|
||||
$pct = $results[0];
|
||||
$this->assertEqual(50, $pct['file']['percentage']);
|
||||
$this->assertEqual('file.html', $pct['file']['byFileReport']);
|
||||
}
|
||||
|
||||
function testTotalLoc() {
|
||||
$this->assertEqual(13, $this->calc->totalLoc(10, array(1,2,3)));
|
||||
}
|
||||
|
||||
function testLineCoverage() {
|
||||
$this->assertEqual(10, $this->calc->lineCoverage(10, -1));
|
||||
$this->assertEqual(10, $this->calc->lineCoverage(10, 0));
|
||||
$this->assertEqual(11, $this->calc->lineCoverage(10, 1));
|
||||
}
|
||||
|
||||
function testTotalCoverage() {
|
||||
$this->assertEqual(11, $this->calc->totalCoverage(10, array(-1,1)));
|
||||
}
|
||||
|
||||
static function getAttribute($element, $attribute) {
|
||||
$a = $element->attributes();
|
||||
return $a[$attribute];
|
||||
}
|
||||
|
||||
static function dom($stream) {
|
||||
rewind($stream);
|
||||
$actual = stream_get_contents($stream);
|
||||
$html = DOMDocument::loadHTML($actual);
|
||||
return simplexml_import_dom($html);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
require_once(dirname(__FILE__) . '/../../../autorun.php');
|
||||
|
||||
class CoverageDataHandlerTest extends UnitTestCase {
|
||||
function skip() {
|
||||
$this->skipIf(
|
||||
!file_exists('DB/sqlite.php'),
|
||||
'The Coverage extension needs to have PEAR installed');
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
require_once dirname(__FILE__) .'/../coverage_data_handler.php';
|
||||
}
|
||||
|
||||
function testAggregateCoverageCode() {
|
||||
$handler = new CoverageDataHandler($this->tempdb());
|
||||
$this->assertEqual(-2, $handler->aggregateCoverageCode(-2, -2));
|
||||
$this->assertEqual(-2, $handler->aggregateCoverageCode(-2, 10));
|
||||
$this->assertEqual(-2, $handler->aggregateCoverageCode(10, -2));
|
||||
$this->assertEqual(-1, $handler->aggregateCoverageCode(-1, -1));
|
||||
$this->assertEqual(10, $handler->aggregateCoverageCode(-1, 10));
|
||||
$this->assertEqual(10, $handler->aggregateCoverageCode(10, -1));
|
||||
$this->assertEqual(20, $handler->aggregateCoverageCode(10, 10));
|
||||
}
|
||||
|
||||
function testSimpleWriteRead() {
|
||||
$handler = new CoverageDataHandler($this->tempdb());
|
||||
$handler->createSchema();
|
||||
$coverage = array(10 => -2, 20 => -1, 30 => 0, 40 => 1);
|
||||
$handler->write(array('file' => $coverage));
|
||||
|
||||
$actual = $handler->readFile('file');
|
||||
$expected = array(10 => -2, 20 => -1, 30 => 0, 40 => 1);
|
||||
$this->assertEqual($expected, $actual);
|
||||
}
|
||||
|
||||
function testMultiFileWriteRead() {
|
||||
$handler = new CoverageDataHandler($this->tempdb());
|
||||
$handler->createSchema();
|
||||
$handler->write(array(
|
||||
'file1' => array(-2, -1, 1),
|
||||
'file2' => array(-2, -1, 1)
|
||||
));
|
||||
$handler->write(array(
|
||||
'file1' => array(-2, -1, 1)
|
||||
));
|
||||
|
||||
$expected = array(
|
||||
'file1' => array(-2, -1, 2),
|
||||
'file2' => array(-2, -1, 1)
|
||||
);
|
||||
$actual = $handler->read();
|
||||
$this->assertEqual($expected, $actual);
|
||||
}
|
||||
|
||||
function testGetfilenames() {
|
||||
$handler = new CoverageDataHandler($this->tempdb());
|
||||
$handler->createSchema();
|
||||
$rawCoverage = array('file0' => array(), 'file1' => array());
|
||||
$handler->write($rawCoverage);
|
||||
$actual = $handler->getFilenames();
|
||||
$this->assertEqual(array('file0', 'file1'), $actual);
|
||||
}
|
||||
|
||||
function testWriteUntouchedFiles() {
|
||||
$handler = new CoverageDataHandler($this->tempdb());
|
||||
$handler->createSchema();
|
||||
$handler->writeUntouchedFile('bluejay');
|
||||
$handler->writeUntouchedFile('robin');
|
||||
$this->assertEqual(array('bluejay', 'robin'), $handler->readUntouchedFiles());
|
||||
}
|
||||
|
||||
function testLtrim() {
|
||||
$this->assertEqual('ber', CoverageDataHandler::ltrim('goo', 'goober'));
|
||||
$this->assertEqual('some/file', CoverageDataHandler::ltrim('./', './some/file'));
|
||||
$this->assertEqual('/x/y/z/a/b/c', CoverageDataHandler::ltrim('/a/b/', '/x/y/z/a/b/c'));
|
||||
}
|
||||
|
||||
function tempdb() {
|
||||
return tempnam(NULL, 'coverage.test.db');
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
require_once(dirname(__FILE__) . '/../../../autorun.php');
|
||||
|
||||
class CoverageReporterTest extends UnitTestCase {
|
||||
function skip() {
|
||||
$this->skipIf(
|
||||
!file_exists('DB/sqlite.php'),
|
||||
'The Coverage extension needs to have PEAR installed');
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
require_once dirname(__FILE__) .'/../coverage_reporter.php';
|
||||
new CoverageReporter();
|
||||
}
|
||||
|
||||
function testreportFilename() {
|
||||
$this->assertEqual("parula.php.html", CoverageReporter::reportFilename("parula.php"));
|
||||
$this->assertEqual("warbler_parula.php.html", CoverageReporter::reportFilename("warbler/parula.php"));
|
||||
$this->assertEqual("warbler_parula.php.html", CoverageReporter::reportFilename("warbler\\parula.php"));
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
require_once(dirname(__FILE__) . '/../../../autorun.php');
|
||||
require_once(dirname(__FILE__) . '/../../../mock_objects.php');
|
||||
|
||||
class CodeCoverageTest extends UnitTestCase {
|
||||
function skip() {
|
||||
$this->skipIf(
|
||||
!file_exists('DB/sqlite.php'),
|
||||
'The Coverage extension needs to have PEAR installed');
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
require_once dirname(__FILE__) .'/../coverage.php';
|
||||
}
|
||||
|
||||
function testIsFileIncluded() {
|
||||
$coverage = new CodeCoverage();
|
||||
$this->assertTrue($coverage->isFileIncluded('aaa'));
|
||||
$coverage->includes = array('a');
|
||||
$this->assertTrue($coverage->isFileIncluded('aaa'));
|
||||
$coverage->includes = array('x');
|
||||
$this->assertFalse($coverage->isFileIncluded('aaa'));
|
||||
$coverage->excludes = array('aa');
|
||||
$this->assertFalse($coverage->isFileIncluded('aaa'));
|
||||
}
|
||||
|
||||
function testIsFileIncludedRegexp() {
|
||||
$coverage = new CodeCoverage();
|
||||
$coverage->includes = array('modules/.*\.php$');
|
||||
$coverage->excludes = array('bad-bunny.php');
|
||||
$this->assertFalse($coverage->isFileIncluded('modules/a.test'));
|
||||
$this->assertFalse($coverage->isFileIncluded('modules/bad-bunny.test'));
|
||||
$this->assertTrue($coverage->isFileIncluded('modules/test.php'));
|
||||
$this->assertFalse($coverage->isFileIncluded('module-bad/good-bunny.php'));
|
||||
$this->assertTrue($coverage->isFileIncluded('modules/good-bunny.php'));
|
||||
}
|
||||
|
||||
function testIsDirectoryIncludedPastMaxDepth() {
|
||||
$coverage = new CodeCoverage();
|
||||
$coverage->maxDirectoryDepth = 5;
|
||||
$this->assertTrue($coverage->isDirectoryIncluded('aaa', 1));
|
||||
$this->assertFalse($coverage->isDirectoryIncluded('aaa', 5));
|
||||
}
|
||||
|
||||
function testIsDirectoryIncluded() {
|
||||
$coverage = new CodeCoverage();
|
||||
$this->assertTrue($coverage->isDirectoryIncluded('aaa', 0));
|
||||
$coverage->excludes = array('b$');
|
||||
$this->assertTrue($coverage->isDirectoryIncluded('aaa', 0));
|
||||
$coverage->includes = array('a$'); // includes are ignore, all dirs are included unless excluded
|
||||
$this->assertTrue($coverage->isDirectoryIncluded('aaa', 0));
|
||||
$coverage->excludes = array('.*a$');
|
||||
$this->assertFalse($coverage->isDirectoryIncluded('aaa', 0));
|
||||
}
|
||||
|
||||
function testFilter() {
|
||||
$coverage = new CodeCoverage();
|
||||
$data = array('a' => 0, 'b' => 0, 'c' => 0);
|
||||
$coverage->includes = array('b');
|
||||
$coverage->filter($data);
|
||||
$this->assertEqual(array('b' => 0), $data);
|
||||
}
|
||||
|
||||
function testUntouchedFiles() {
|
||||
$coverage = new CodeCoverage();
|
||||
$touched = array_flip(array("test/coverage_test.php"));
|
||||
$actual = array();
|
||||
$coverage->includes = array('coverage_test\.php$');
|
||||
$parentDir = realpath(dirname(__FILE__));
|
||||
$coverage->getUntouchedFiles($actual, $touched, $parentDir, $parentDir);
|
||||
$this->assertEqual(array("coverage_test.php"), $actual);
|
||||
}
|
||||
|
||||
function testResetLog() {
|
||||
$coverage = new CodeCoverage();
|
||||
$coverage->log = tempnam(NULL, 'php.xdebug.coverage.test.');
|
||||
$coverage->resetLog();
|
||||
$this->assertTrue(file_exists($coverage->log));
|
||||
}
|
||||
|
||||
function testSettingsSerialization() {
|
||||
$coverage = new CodeCoverage();
|
||||
$coverage->log = '/banana/boat';
|
||||
$coverage->includes = array('apple', 'orange');
|
||||
$coverage->excludes = array('tomato', 'pea');
|
||||
$data = $coverage->getSettings();
|
||||
$this->assertNotNull($data);
|
||||
|
||||
$actual = new CodeCoverage();
|
||||
$actual->setSettings($data);
|
||||
$this->assertEqual('/banana/boat', $actual->log);
|
||||
$this->assertEqual(array('apple', 'orange'), $actual->includes);
|
||||
$this->assertEqual(array('tomato', 'pea'), $actual->excludes);
|
||||
}
|
||||
|
||||
function testSettingsCanBeReadWrittenToDisk() {
|
||||
$settings_file = 'banana-boat-coverage-settings-test.dat';
|
||||
$coverage = new CodeCoverage();
|
||||
$coverage->log = '/banana/boat';
|
||||
$coverage->settingsFile = $settings_file;
|
||||
$coverage->writeSettings();
|
||||
|
||||
$actual = new CodeCoverage();
|
||||
$actual->settingsFile = $settings_file;
|
||||
$actual->readSettings();
|
||||
$this->assertEqual('/banana/boat', $actual->log);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
require_once dirname(__FILE__) . '/../../../autorun.php';
|
||||
|
||||
class CoverageUtilsTest extends UnitTestCase {
|
||||
function skip() {
|
||||
$this->skipIf(
|
||||
!file_exists('DB/sqlite.php'),
|
||||
'The Coverage extension needs to have PEAR installed');
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
require_once dirname(__FILE__) .'/../coverage_utils.php';
|
||||
}
|
||||
|
||||
function testMkdir() {
|
||||
CoverageUtils::mkdir(dirname(__FILE__));
|
||||
try {
|
||||
CoverageUtils::mkdir(__FILE__);
|
||||
$this->fail("Should give error about cannot create dir of a file");
|
||||
} catch (Exception $expected) {
|
||||
}
|
||||
}
|
||||
|
||||
function testIsPackageClassAvailable() {
|
||||
$coverageSource = dirname(__FILE__) .'/../coverage_calculator.php';
|
||||
$this->assertTrue(CoverageUtils::isPackageClassAvailable($coverageSource, 'CoverageCalculator'));
|
||||
$this->assertFalse(CoverageUtils::isPackageClassAvailable($coverageSource, 'BogusCoverage'));
|
||||
$this->assertFalse(CoverageUtils::isPackageClassAvailable('bogus-file', 'BogusCoverage'));
|
||||
$this->assertTrue(CoverageUtils::isPackageClassAvailable('bogus-file', 'CoverageUtils'));
|
||||
}
|
||||
|
||||
function testParseArgumentsMultiValue() {
|
||||
$actual = CoverageUtils::parseArguments(array('scriptname', '--a=b', '--a=c'), True);
|
||||
$expected = array('extraArguments' => array(), 'a' => 'c', 'a[]' => array('b', 'c'));
|
||||
$this->assertEqual($expected, $actual);
|
||||
}
|
||||
|
||||
function testParseArguments() {
|
||||
$actual = CoverageUtils::parseArguments(array('scriptname', '--a=b', '-c', 'xxx'));
|
||||
$expected = array('a' => 'b', 'c' => '', 'extraArguments' => array('xxx'));
|
||||
$this->assertEqual($expected, $actual);
|
||||
}
|
||||
|
||||
function testParseDoubleDashNoArguments() {
|
||||
$actual = CoverageUtils::parseArguments(array('scriptname', '--aa'));
|
||||
$this->assertTrue(isset($actual['aa']));
|
||||
}
|
||||
|
||||
function testParseHyphenedExtraArguments() {
|
||||
$actual = CoverageUtils::parseArguments(array('scriptname', '--alpha-beta=b', 'gamma-lambda'));
|
||||
$expected = array('alpha-beta' => 'b', 'extraArguments' => array('gamma-lambda'));
|
||||
$this->assertEqual($expected, $actual);
|
||||
}
|
||||
|
||||
function testAddItemAsArray() {
|
||||
$actual = array();
|
||||
CoverageUtils::addItemAsArray($actual, 'bird', 'duck');
|
||||
$this->assertEqual(array('bird[]' => array('duck')), $actual);
|
||||
|
||||
CoverageUtils::addItemAsArray(&$actual, 'bird', 'pigeon');
|
||||
$this->assertEqual(array('bird[]' => array('duck', 'pigeon')), $actual);
|
||||
}
|
||||
|
||||
function testIssetOr() {
|
||||
$data = array('bird' => 'gull');
|
||||
$this->assertEqual('lab', CoverageUtils::issetOr($data['dog'], 'lab'));
|
||||
$this->assertEqual('gull', CoverageUtils::issetOr($data['bird'], 'sparrow'));
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
// sample code
|
||||
$x = 1 + 2;
|
||||
if (false) echo "dead";
|
69
3rdparty/simpletest/extensions/coverage/test/simple_coverage_writer_test.php
vendored
Normal file
69
3rdparty/simpletest/extensions/coverage/test/simple_coverage_writer_test.php
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
require_once(dirname(__FILE__) . '/../../../autorun.php');
|
||||
|
||||
class SimpleCoverageWriterTest extends UnitTestCase {
|
||||
function skip() {
|
||||
$this->skipIf(
|
||||
!file_exists('DB/sqlite.php'),
|
||||
'The Coverage extension needs to have PEAR installed');
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
require_once dirname(__FILE__) .'/../simple_coverage_writer.php';
|
||||
require_once dirname(__FILE__) .'/../coverage_calculator.php';
|
||||
|
||||
}
|
||||
|
||||
function testGenerateSummaryReport() {
|
||||
$writer = new SimpleCoverageWriter();
|
||||
$coverage = array('file' => array(0, 1));
|
||||
$untouched = array('missed-file');
|
||||
$calc = new CoverageCalculator();
|
||||
$variables = $calc->variables($coverage, $untouched);
|
||||
$variables['title'] = 'coverage';
|
||||
$out = fopen("php://memory", 'w');
|
||||
$writer->writeSummary($out, $variables);
|
||||
$dom = self::dom($out);
|
||||
$totalPercentCoverage = $dom->elements->xpath("//span[@class='totalPercentCoverage']");
|
||||
$this->assertEqual('50%', (string)$totalPercentCoverage[0]);
|
||||
|
||||
$fileLinks = $dom->elements->xpath("//a[@class='byFileReportLink']");
|
||||
$fileLinkAttr = $fileLinks[0]->attributes();
|
||||
$this->assertEqual('file.html', $fileLinkAttr['href']);
|
||||
$this->assertEqual('file', (string)($fileLinks[0]));
|
||||
|
||||
$untouchedFile = $dom->elements->xpath("//span[@class='untouchedFile']");
|
||||
$this->assertEqual('missed-file', (string)$untouchedFile[0]);
|
||||
}
|
||||
|
||||
function testGenerateCoverageByFile() {
|
||||
$writer = new SimpleCoverageWriter();
|
||||
$cov = array(3 => 1, 4 => -2); // 2 comments, 1 code, 1 dead (1-based indexes)
|
||||
$out = fopen("php://memory", 'w');
|
||||
$file = dirname(__FILE__) .'/sample/code.php';
|
||||
$calc = new CoverageCalculator();
|
||||
$variables = $calc->coverageByFileVariables($file, $cov);
|
||||
$variables['title'] = 'coverage';
|
||||
$writer->writeByFile($out, $variables);
|
||||
$dom = self::dom($out);
|
||||
|
||||
$cells = $dom->elements->xpath("//table[@id='code']/tbody/tr/td/span");
|
||||
$this->assertEqual("comment code", self::getAttribute($cells[1], 'class'));
|
||||
$this->assertEqual("comment code", self::getAttribute($cells[3], 'class'));
|
||||
$this->assertEqual("covered code", self::getAttribute($cells[5], 'class'));
|
||||
$this->assertEqual("dead code", self::getAttribute($cells[7], 'class'));
|
||||
}
|
||||
|
||||
static function getAttribute($element, $attribute) {
|
||||
$a = $element->attributes();
|
||||
return $a[$attribute];
|
||||
}
|
||||
|
||||
static function dom($stream) {
|
||||
rewind($stream);
|
||||
$actual = stream_get_contents($stream);
|
||||
$html = DOMDocument::loadHTML($actual);
|
||||
return simplexml_import_dom($html);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
// $Id: $
|
||||
require_once(dirname(__FILE__) . '/../../../autorun.php');
|
||||
|
||||
class CoverageUnitTests extends TestSuite {
|
||||
function CoverageUnitTests() {
|
||||
$this->TestSuite('Coverage Unit tests');
|
||||
$path = dirname(__FILE__) . '/*_test.php';
|
||||
foreach(glob($path) as $test) {
|
||||
$this->addFile($test);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
Loading…
Reference in New Issue