painter = $painter; $this->base_dir = $base_dir; } function paintHeader($test_name, $charset="UTF-8") { $this->sendNoCacheHeaders(); header('Content-Type: text/html; Charset='.$charset); print "\n\n$test_name\n"; print ""; print "\n"; print "\n\n"; print "

$test_name

\n"; flush(); if (extension_loaded('xdebug')) xdebug_start_code_coverage(XDEBUG_CC_UNUSED); } /** * */ function _getCss() { $contents = parent::_getCss()."\n "; $contents .= ' .bar { float: left; display: inline; border: 1px solid #eee; width: 300px; white-space: nowrap;} .percentage { float: left; background-color: #eef; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 0.65em; padding: 5px; margin-right: } .coverage {margin: 0.4em; } .coverage a { padding-left: 0.5em; } .coverage:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } .coverage {display: inline-block;} /* Hides from IE-mac \*/ * html .coverage {height: 1%;} .coverage {display: block;} /* End hide from IE-mac */ '; Return $contents; } function paintFooter($test_name) { if (extension_loaded('xdebug')) { $this->coverage = xdebug_get_code_coverage(); xdebug_stop_code_coverage(); } $colour = ($this->getFailCount() + $this->getExceptionCount() > 0 ? "red" : "green"); print "
"; print $this->getTestCaseProgress() . "/" . $this->getTestCaseCount(); print " test cases complete:\n"; print "" . $this->getPassCount() . " passes, "; print "" . $this->getFailCount() . " fails and "; print "" . $this->getExceptionCount() . " exceptions."; print "
\n"; $this->paintCoverage(); print "\n\n"; } function paintCoverage() { $dir = dirname(__FILE__); if(count($this->coverage) > 0) print '

Code Coverage

'; ksort($this->coverage); $details = array(); foreach($this->coverage as $file => $coverage) { if(is_int(strpos($file, $dir)) == false && is_int(strpos($file, 'simpletest')) == false && is_int(strpos($file, $this->base_dir))) { $total = HTMLCoverageReport::codelines($file); $executed = count($coverage); $percentage = sprintf('%01d',$executed/$total*100); $width = $percentage * 3; $filename = str_replace($this->base_dir, '',$file); $link = $this->constructURL($filename, $coverage); $detail['total'] = $total; $detail['executed'] = $executed; $detail['width'] = $width; $detail['filename'] = $filename; $detail['link'] = $link; $details[$percentage][] = $detail; } } krsort($details); foreach($details as $percentage => $files) { foreach($files as $detail) { $total = $detail['total']; $executed = $detail['executed']; $width = $detail['width']; $filename = $detail['filename']; $link = $detail['link']; print "
"; print ""; print ""; print "$executed/$total\n"; print "$percentage%\n"; print "{$filename}\n"; print "
\n"; } } } function constructURL($file, $coverage) { $file = rawurlencode($file); $lines = implode(',', array_keys($coverage)); return $this->painter.'?file='.$file.'&lines='.$lines; } } class HTMLCoverageReport extends HtmlReporter { protected $file; protected $lines; protected $name; function __construct($file, $name, $lines) { $this->file = $file; $this->lines = $lines; $this->name = $name; } function show() { $this->paintHeader($this->name); $contents = file($this->file); foreach($contents as $count => $line) { $num = ($count+1); $line = preg_replace("/\\n|\\r/",'',$line); $line = htmlspecialchars($line); $line = str_replace(' ',' ',$line); $line = str_replace("\t",'    ',$line); if(in_array($count+1, $this->lines)) echo "
$num $line
\n"; else echo "$num $line
\n"; } $this->paintFooter(); } function paintHeader($file, $charset="UTF-8") { $total = $this->codelines($this->file); $executed = count($this->lines); $percentage = sprintf('%01.2f',$executed/$total*100); $this->sendNoCacheHeaders(); header('Content-Type: text/html Charset='.$charset); print "\n\nCode Coverage: $file\n"; print ""; print "\n"; print "\n\n"; print "

Code Coverage

\n"; print "
$file
"; print "
    Total code lines: {$total}
Total lines executed: {$executed} ({$percentage}%)
"; flush(); } function paintFooter($test_name) { print "\n\n"; } static function codelines($file) { $source = file_get_contents($file); $tokens = @token_get_all($source); $lines = ''; foreach ($tokens as $token) { if (is_string($token)) { // simple 1-character token $lines .= $token; } else { // token array list($id, $text) = $token; switch ($id) { case T_COMMENT: case T_ML_COMMENT: // we've defined this case T_DOC_COMMENT: // and this // no action on comments break; default: // anything else -> output "as is" //echo $text; $lines .= $text; break; } } } $lines = preg_replace('/\\n\s*$/m',"",$lines); $codelines = explode("\n",$lines); $count = 0; $patterns[] = '^\s*{\s*$'; $patterns[] = '<\?'; $patterns[] = '^\s*(private|protected|public)\s+\$'; $pattern = '/'.implode('|', $patterns).'/'; foreach($codelines as $line) { if(!preg_match($pattern, $line)) $count++; } return $count; //var_dump($codelines); //return count($codelines); } }