Commit 61399a52 authored by meus's avatar meus

added spikephpcoverage but did not get it to work. if somebody wants to play...

added spikephpcoverage but did not get it to work. if somebody wants to play with it look in DoctrineTest on line 122. fixed the coverage report a little
parent 3cea839f
...@@ -118,6 +118,29 @@ class DoctrineTest ...@@ -118,6 +118,29 @@ class DoctrineTest
//generate coverage report //generate coverage report
if (isset($options['coverage'])) { if (isset($options['coverage'])) {
/*
* The below code will not work for me (meus). It would be nice if
* somebody could give it a try. Just replace this block of code
* with the one below
*
define('PHPCOVERAGE_HOME', dirname(dirname(__FILE__)) . '/vendor/spikephpcoverage');
require_once PHPCOVERAGE_HOME . '/CoverageRecorder.php';
require_once PHPCOVERAGE_HOME . '/reporter/HtmlCoverageReporter.php';
$covReporter = new HtmlCoverageReporter('Doctrine Code Coverage Report', '', 'coverage2');
$includePaths = array('../lib');
$excludePaths = array();
$cov = new CoverageRecorder($includePaths, $excludePaths, $covReporter);
$cov->startInstrumentation();
$testGroup->run($reporter, $filter);
$cov->stopInstrumentation();
$cov->generateReport();
$covReporter->printTextSummary();
*/
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE); xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
$testGroup->run($reporter, $filter); $testGroup->run($reporter, $filter);
$result['coverage'] = xdebug_get_code_coverage(); $result['coverage'] = xdebug_get_code_coverage();
...@@ -126,6 +149,7 @@ class DoctrineTest ...@@ -126,6 +149,7 @@ class DoctrineTest
require_once dirname(__FILE__) . '/DoctrineTest/Coverage.php'; require_once dirname(__FILE__) . '/DoctrineTest/Coverage.php';
$coverageGeneration = new DoctrineTest_Coverage(); $coverageGeneration = new DoctrineTest_Coverage();
$coverageGeneration->generateReport(); $coverageGeneration->generateReport();
// */
} else { } else {
$testGroup->run($reporter, $filter); $testGroup->run($reporter, $filter);
} }
......
...@@ -98,13 +98,14 @@ class DoctrineTest_Coverage ...@@ -98,13 +98,14 @@ class DoctrineTest_Coverage
$totals['notcovered'] , '</td><td></tr>'; $totals['notcovered'] , '</td><td></tr>';
foreach($coveredArray as $class => $info){ foreach($coveredArray as $class => $info){
echo '<tr><td>' . $class . '</td><td>' . $info['percentage'] . ' % </td><td>' . $info['total'] . '</td><td>' . $info['covered'] . '</td><td>' . $info['maybe'] . '</td><td>' . $info['notcovered']. '</td>';
echo '<tr><td>';
if ( $info['type'] == "covered") { if ( $info['type'] == "covered") {
echo '<td><a href="' , $class , '.html">', $class , '</a></td>'; echo '<a href="' , $class , '.html">', $class , '</a>';
} else { }else{
echo '<td>not tested</td>'; echo $class;
} }
echo '</tr>'; echo '<td>' . $info['percentage'] . ' % </td><td>' . $info['total'] . '</td><td>' . $info['covered'] . '</td><td>' . $info['maybe'] . '</td><td>' . $info['notcovered']. '</td></tr>';
} }
} }
......
...@@ -40,6 +40,7 @@ $revision = $svn_info[1]; ...@@ -40,6 +40,7 @@ $revision = $svn_info[1];
<h1>Coverage report for Doctrine</h1> <h1>Coverage report for Doctrine</h1>
<p>Report generated against revision <?php echo $reporter->getRevision(); ?> current HEAD revision is <?php echo $revision ?>.</p> <p>Report generated against revision <?php echo $reporter->getRevision(); ?> current HEAD revision is <?php echo $revision ?>.</p>
<p>Default mode shows results sorted by percentage with highest first. Customize the ordering with the following GET parameters:<br /> <ul><li>order = covered|total|maybe|notcovered|percentage</li><li>flip=true</li></ul></p> <p>Default mode shows results sorted by percentage with highest first. Customize the ordering with the following GET parameters:<br /> <ul><li>order = covered|total|maybe|notcovered|percentage</li><li>flip=true</li></ul></p>
<p>Files that are not linked in the below table are not tested at all.</p>
<table> <table>
<tr> <tr>
<th></th> <th></th>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2004 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 3.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/3_0.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Stephan Schmidt <schst@php-tools.net> |
// +----------------------------------------------------------------------+
//
// $Id: Simple.php,v 1.6 2005/03/25 17:13:10 schst Exp $
/**
* Simple XML parser class.
*
* This class is a simplified version of XML_Parser.
* In most XML applications the real action is executed,
* when a closing tag is found.
*
* XML_Parser_Simple allows you to just implement one callback
* for each tag that will receive the tag with its attributes
* and CData
*
* @category XML
* @package XML_Parser
* @author Stephan Schmidt <schst@php-tools.net>
*/
/**
* built on XML_Parser
*/
require_once 'XML/Parser.php';
/**
* Simple XML parser class.
*
* This class is a simplified version of XML_Parser.
* In most XML applications the real action is executed,
* when a closing tag is found.
*
* XML_Parser_Simple allows you to just implement one callback
* for each tag that will receive the tag with its attributes
* and CData.
*
* <code>
* require_once '../Parser/Simple.php';
*
* class myParser extends XML_Parser_Simple
* {
* function myParser()
* {
* $this->XML_Parser_Simple();
* }
*
* function handleElement($name, $attribs, $data)
* {
* printf('handle %s<br>', $name);
* }
* }
*
* $p = &new myParser();
*
* $result = $p->setInputFile('myDoc.xml');
* $result = $p->parse();
* </code>
*
* @category XML
* @package XML_Parser
* @author Stephan Schmidt <schst@php-tools.net>
*/
class XML_Parser_Simple extends XML_Parser
{
/**
* element stack
*
* @access private
* @var array
*/
var $_elStack = array();
/**
* all character data
*
* @access private
* @var array
*/
var $_data = array();
/**
* element depth
*
* @access private
* @var integer
*/
var $_depth = 0;
/**
* Mapping from expat handler function to class method.
*
* @var array
*/
var $handler = array(
'default_handler' => 'defaultHandler',
'processing_instruction_handler' => 'piHandler',
'unparsed_entity_decl_handler' => 'unparsedHandler',
'notation_decl_handler' => 'notationHandler',
'external_entity_ref_handler' => 'entityrefHandler'
);
/**
* Creates an XML parser.
*
* This is needed for PHP4 compatibility, it will
* call the constructor, when a new instance is created.
*
* @param string $srcenc source charset encoding, use NULL (default) to use
* whatever the document specifies
* @param string $mode how this parser object should work, "event" for
* handleElement(), "func" to have it call functions
* named after elements (handleElement_$name())
* @param string $tgenc a valid target encoding
*/
function XML_Parser_Simple($srcenc = null, $mode = 'event', $tgtenc = null)
{
$this->XML_Parser($srcenc, $mode, $tgtenc);
}
/**
* inits the handlers
*
* @access private
*/
function _initHandlers()
{
if (!is_object($this->_handlerObj)) {
$this->_handlerObj = &$this;
}
if ($this->mode != 'func' && $this->mode != 'event') {
return $this->raiseError('Unsupported mode given', XML_PARSER_ERROR_UNSUPPORTED_MODE);
}
xml_set_object($this->parser, $this->_handlerObj);
xml_set_element_handler($this->parser, array(&$this, 'startHandler'), array(&$this, 'endHandler'));
xml_set_character_data_handler($this->parser, array(&$this, 'cdataHandler'));
/**
* set additional handlers for character data, entities, etc.
*/
foreach ($this->handler as $xml_func => $method) {
if (method_exists($this->_handlerObj, $method)) {
$xml_func = 'xml_set_' . $xml_func;
$xml_func($this->parser, $method);
}
}
}
/**
* Reset the parser.
*
* This allows you to use one parser instance
* to parse multiple XML documents.
*
* @access public
* @return boolean|object true on success, PEAR_Error otherwise
*/
function reset()
{
$this->_elStack = array();
$this->_data = array();
$this->_depth = 0;
$result = $this->_create();
if ($this->isError( $result )) {
return $result;
}
return true;
}
/**
* start handler
*
* Pushes attributes and tagname onto a stack
*
* @access private
* @final
* @param resource xml parser resource
* @param string element name
* @param array attributes
*/
function startHandler($xp, $elem, &$attribs)
{
array_push($this->_elStack, array(
'name' => $elem,
'attribs' => $attribs
)
);
$this->_depth++;
$this->_data[$this->_depth] = '';
}
/**
* end handler
*
* Pulls attributes and tagname from a stack
*
* @access private
* @final
* @param resource xml parser resource
* @param string element name
*/
function endHandler($xp, $elem)
{
$el = array_pop($this->_elStack);
$data = $this->_data[$this->_depth];
$this->_depth--;
switch ($this->mode) {
case 'event':
$this->_handlerObj->handleElement($el['name'], $el['attribs'], $data);
break;
case 'func':
$func = 'handleElement_' . $elem;
if (strchr($func, '.')) {
$func = str_replace('.', '_', $func);
}
if (method_exists($this->_handlerObj, $func)) {
call_user_func(array(&$this->_handlerObj, $func), $el['name'], $el['attribs'], $data);
}
break;
}
}
/**
* handle character data
*
* @access private
* @final
* @param resource xml parser resource
* @param string data
*/
function cdataHandler($xp, $data)
{
$this->_data[$this->_depth] .= $data;
}
/**
* handle a tag
*
* Implement this in your parser
*
* @access public
* @abstract
* @param string element name
* @param array attributes
* @param string character data
*/
function handleElement($name, $attribs, $data)
{
}
/**
* get the current tag depth
*
* The root tag is in depth 0.
*
* @access public
* @return integer
*/
function getCurrentDepth()
{
return $this->_depth;
}
/**
* add some string to the current ddata.
*
* This is commonly needed, when a document is parsed recursively.
*
* @access public
* @param string data to add
* @return void
*/
function addToData( $data )
{
$this->_data[$this->_depth] .= $data;
}
}
?>
This diff is collapsed.
<?php
/*
* $Id: instrument.php 14672 2005-03-23 21:37:47Z npac $
*
* 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);
}
}
}
?>
<?php
/*
* $Id: license.txt 13981 2005-03-16 08:09:28Z eespino $
*
* 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
// Set to 'LOG_DEBUG' for maximum log output
// Note that the log file size will grow rapidly
// with LOG_DEBUG
//$spc_config['log_level'] = 'LOG_NOTICE';
$spc_config['log_level'] = 'LOG_DEBUG';
// file extension to be treated as php files
// comma-separated list, no space
$spc_config['extensions'] = array('php', 'tpl', 'inc');
// temporary directory to save transient files
$spc_config['tmpdir'] = '/tmp';
// temporary directory on Windows machines
$spc_config['windows_tmpdir'] = 'C:/TMP';
?>
<?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
require_once("XML/Parser.php");
if(!defined("ATTRIBUTES")) {
define("ATTRIBUTES", "__ATTRIBUTES__");
}
/**
* An XML parser that extends the functionality of PEAR XML_Parser
* module.
*
* @author Nimish Pachapurkar <npac@spikesource.com>
* @version $Revision: $
* @package SpikePHPCoverage_Parser
*/
class BasicXmlParser extends XML_Parser {
/*{{{ Members */
protected $openTags;
protected $docroot;
/*}}}*/
/*{{{ Constructor*/
/**
* Constructor
* @access public
*/
public function BasicXmlParser() {
parent::XML_Parser();
}
/*}}}*/
/*{{{ public function handleAttrTag() */
/**
* Function that handles an element with attributes.
*
* @param $name Name of the element
* @param $attrs Attributes array (name, value pairs)
* @return Array An element
* @access public
*/
public function handleAttrTag($name, $attrs) {
$tag = array();
foreach($attrs as $attr_name => $value) {
$tag[$attr_name] = $value;
}
return $tag;
}
/*}}}*/
/*{{{ public function startHandler() */
/**
* Function to handle start of an element
*
* @param $xp XMLParser handle
* @param $name Element name
* @param $attributes Attribute array
* @access public
*/
function startHandler($xp, $name, $attributes) {
$this->openTags[] = $name;
}
/*}}}*/
/*{{{ public function endHandler()*/
/**
* Function to handle end of an element
*
* @param $xp XML_Parser handle
* @param $name Name of the element
* @access public
*/
public function endHandler($xp, $name) {
// Handle error tags
$lastTag = $this->getLastOpenTag($name);
switch($name) {
case "MESSAGE":
if($lastTag == "ERROR") {
$this->docroot["ERROR"]["MESSAGE"] = $this->getCData();
}
break;
}
// Empty CData
$this->lastCData = "";
// Close tag
if($this->openTags[count($this->openTags)-1] == $name) {
array_pop($this->openTags);
}
}
/*}}}*/
/*{{{ public function cdataHandler() */
/**
* Function to handle character data
*
* @param $xp XMLParser handle
* @param $cdata Character data
* @access public
*/
public function cdataHandler($xp, $cdata) {
$this->lastCData .= $cdata;
}
/*}}}*/
/*{{{ public function getCData() */
/**
* Returns the CData collected so far.
*
* @return String Character data collected.
* @access public
*/
public function getCData() {
return $this->lastCData;
}
/*}}}*/
/*{{{ public function getLastOpenTag() */
/**
* Returns the name of parent tag of give tag
*
* @param $tag Name of a child tag
* @return String Name of the parent tag of $tag
* @access public
*/
public function getLastOpenTag($tag) {
$lastTagIndex = count($this->openTags)-1;
if($this->openTags[$lastTagIndex] == $tag) {
if($lastTagIndex > 0) {
return $this->openTags[$lastTagIndex-1];
}
}
return false;
}
/*}}}*/
/*{{{ public function getDocumentArray() */
/**
* Return the document array gathered during parsing.
* Document array is a data structure that mimics the XML
* contents.
*
* @return Array Document array
* @access public
*/
public function getDocumentArray() {
return $this->docroot;
}
/*}}}*/
}
?>
<?php
/*
* $Id: CoverageXmlParser.php 14663 2005-03-23 19:27:27Z npac $
*
* 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
require_once dirname(__FILE__) . "/BasicXmlParser.php";
/**
* Special parser for SpikePHPCoverage data parsing
* Expect input in following format:
* <spike-phpcoverage>
* <file path="/complete/file/path">
* <line line-number="10" frequency="1"/>
* <line line-number="12" frequency="2"/>
* </file>
* <file path="/another/file/path">
* ...
* </file>
* </spike-phpcoverage>
*
* @author Nimish Pachapurkar <npac@spikesource.com>
* @version $Revision: $
* @package SpikePHPCoverage_Parser
*/
class CoverageXmlParser extends BasicXmlParser {
/*{{{ Members */
protected $_data = array();
protected $_lastFilePath;
/*}}}*/
/*{{{ public function startHandler() */
public function startHandler($xp, $name, $attrs) {
switch($name) {
case "FILE":
$fileAttributes = $this->handleAttrTag($name, $attrs);
$this->_lastFilePath = $fileAttributes["PATH"];
if(!isset($this->_data[$this->_lastFilePath])) {
$this->_data[$this->_lastFilePath] = array();
}
break;
case "LINE":
$lineAttributes = $this->handleAttrTag($name, $attrs);
$lineNumber = (int)$lineAttributes["LINE-NUMBER"];
if(!isset($this->_data[$this->_lastFilePath][$lineNumber])) {
$this->_data[$this->_lastFilePath][$lineNumber] = (int)$lineAttributes["FREQUENCY"];
}
else {
$this->_data[$this->_lastFilePath][$lineNumber] += (int)$lineAttributes["FREQUENCY"];
}
break;
}
}
/*}}}*/
/*{{{ public function getCoverageData() */
/**
* Returns coverage data array from the XML
* Format:
* Array
* (
* [/php/src/remote/RemoteCoverageRecorder.php] => Array
* (
* [220] => 1
* [221] => 1
* )
*
* [/opt/oss/share/apache2/htdocs/web/sample.php] => Array
* (
* [16] => 1
* [18] => 1
* )
* )
*
* @access public
*/
public function getCoverageData() {
return $this->_data;
}
/*}}}*/
}
?>
This diff is collapsed.
<?php
/*
* $Id: Parser.php 14009 2005-03-16 17:33:33Z npac $
*
* 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
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";
/**
* Base class for Parsers.
*
* @author Nimish Pachapurkar (npac@spikesource.com)
* @version $Revision: 14009 $
* @package SpikePHPCoverage_Parser
*/
define("LINE_TYPE_UNKNOWN", "0");
define("LINE_TYPE_EXEC", "1");
define("LINE_TYPE_NOEXEC", "2");
define("LINE_TYPE_CONT", "3");
abstract class Parser {
/*{{{ Members */
protected $totalLines;
protected $coveredLines;
protected $uncoveredLines;
protected $fileRef;
protected $filename;
protected $line;
protected $logger;
/*}}}*/
/*{{{ public function __construct() */
/**
* Constructor
* @access public
*/
public function __construct() {
global $util;
$this->totalLines = 0;
$this->coveredLines = 0;
$this->uncoveredLines = 0;
$this->fileRef = false;
$this->line = false;
$this->lineType = false;
$this->logger = $util->getLogger();
}
/*}}}*/
/*{{{ public abstract function parse() */
/**
* Parse a given file
*
* @param $filename Full path of the file
* @return FALSE on error.
* @access public
*/
public function parse($filename) {
$this->filename = $filename;
$ret = $this->openFileReadOnly();
if(!$ret) {
die("Error: Cannot open file: $this->filename \n");
}
}
/*}}}*/
/*{{{ protected abstract function processLine() */
/**
* Process the line and classify it into either
* covered and uncovered.
*
* @param $line
* @return
* @access protected
*/
protected abstract function processLine($line);
/*}}}*/
/*{{{ public function getLine() */
/**
* Returns the next line from file.
*
* @return Next line from file
* @access public
*/
public function getLine() {
if(!feof($this->fileRef)) {
$this->line = fgets($this->fileRef);
$this->processLine($this->line);
}
else {
fclose($this->fileRef);
$this->line = false;
}
return $this->line;
}
/*}}}*/
/*{{{ public abstract function getLineType() */
/**
* Returns the type of last line read.
*
* The type can be either
* * LINE_TYPE_EXEC Line that can be executed.
* * LINE_TYPE_NOEXEC Line that cannot be executed.
* This includes the variable and function definitions
* (without initialization), blank lines, non-PHP lines,
* etc.
*
* @return Type of last line
* @access public
*/
public abstract function getLineType();
/*}}}*/
/*{{{ public function getLineTypeStr() */
/**
* Returns the string representation of LINE_TYPE
*
* @param $lineType
* @return Type of line
* @access public
*/
public function getLineTypeStr($lineType) {
if($lineType == LINE_TYPE_EXEC) {
return "LINE_TYPE_EXEC";
}
else if($lineType == LINE_TYPE_NOEXEC) {
return "LINE_TYPE_NOEXEC";
}
else if($lineType == LINE_TYPE_CONT) {
return "LINE_TYPE_CONT";
}
else {
return "LINE_TYPE_UNKNOWN";
}
}
/*}}}*/
/*{{{ protected function openFileReadOnly() */
/**
* Opens the file to be parsed in Read-only mode
*
* @return FALSE on failure.
* @access protected
*/
protected function openFileReadOnly() {
$this->fileRef = fopen($this->filename, "r");
return $this->fileRef !== false;
}
/*}}}*/
/*{{{ public function getTotalLines() */
/**
* Returns the total lines (PHP, non-PHP) from a file
*
* @return Number of lines
* @access public
*/
public function getTotalLines() {
return $this->totalLines;
}
/*}}}*/
/*{{{ public function getCoveredLines() */
/**
* Returns the number of covered PHP lines
*
* @return Number of covered lines
* @access public
*/
public function getCoveredLines() {
return $this->coveredLines;
}
/*}}}*/
/*{{{ public function getUncoveredLines() */
/**
* Returns the number of uncovered PHP lines
*
* Note that the sum of covered and uncovered
* lines may not be equal to total lines.
*
* @return Number of uncovered lines
* @access public
*/
public function getUncoveredLines() {
return $this->uncoveredLines;
}
/*}}}*/
}
?>
<?php
/*
* $Id: phpcoverage.inc.php 14670 2005-03-23 21:25:46Z npac $
*
* 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
global $PHPCOVERAGE_REPORT_DIR;
global $PHPCOVERAGE_HOME;
global $PHPCOVERAGE_APPBASE_PATH;
$basedir = dirname(__FILE__);
for($ii=1; $ii < $argc; $ii++) {
if(strpos($argv[$ii], "PHPCOVERAGE_REPORT_DIR=") !== false) {
parse_str($argv[$ii]);
}
else if(strpos($argv[$ii], "PHPCOVERAGE_HOME=") !== false) {
parse_str($argv[$ii]);
}
else if(strpos($argv[$ii], "PHPCOVERAGE_APPBASE_PATH=") !== false) {
parse_str($argv[$ii]);
}
}
if(empty($PHPCOVERAGE_HOME)) {
$envvar = getenv("PHPCOVERAGE_HOME");
if(empty($envvar)) {
$share_home = getenv("LOCAL_CACHE");
$PHPCOVERAGE_HOME = $share_home . "/common/spikephpcoverage/src/";
}
else {
$PHPCOVERAGE_HOME = $envvar;
}
}
if(empty($PHPCOVERAGE_HOME) || !is_dir($PHPCOVERAGE_HOME)) {
$msg = "ERROR: Could not locate PHPCOVERAGE_HOME [$PHPCOVERAGE_HOME]. ";
$msg .= "Use 'php <filename> PHPCOVERAGE_HOME=/path/to/coverage/home'\n";
die($msg);
}
// Fallback
if(!defined("PHPCOVERAGE_HOME")) {
$include_path = get_include_path();
set_include_path($PHPCOVERAGE_HOME. PATH_SEPARATOR . $include_path);
define('PHPCOVERAGE_HOME', $PHPCOVERAGE_HOME);
}
error_log("[phpcoverage.inc.php] PHPCOVERAGE_HOME=" . $PHPCOVERAGE_HOME);
error_log("[phpcoverage.inc.php] PHPCOVERAGE_REPORT_DIR=" . $PHPCOVERAGE_REPORT_DIR);
error_log("[phpcoverage.inc.php] PHPCOVERAGE_APPBASE_PATH=" . $PHPCOVERAGE_APPBASE_PATH);
?>
<?php
/*
* $Id: phpcoverage.remote.bottom.inc.php 14665 2005-03-23 19:37:50Z npac $
*
* 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
if(isset($_REQUEST)) {
global $spc_config, $util;
$logger = $util->getLogger();
// Create a distinct hash (may or may not be unique)
$session_id = md5($_SERVER["REMOTE_ADDR"] . $_SERVER["SERVER_NAME"]);
$tmpFile = $util->getTmpDir() . "/phpcoverage.session." . $session_id;
$logger->info("[phpcoverage.remote.bottom.inc.php] Session id: " . $session_id,
__FILE__, __LINE__);
if(!isset($cov)) {
if(file_exists($tmpFile)) {
$object = file_get_contents($tmpFile);
$cov = unserialize($object);
$logger->info("[phpcoverage.remote.bottom.inc.php] Coverage object found: " . $cov, __FILE__, __LINE__);
}
}
if(isset($cov)) {
// PHPCoverage bottom half
if(!isset($called_script)) {
$called_script = "";
}
$logger->info("[phpcoverage.remote.bottom.inc.php] END: " . $called_script,
__FILE__, __LINE__);
// Save the code coverage
$cov->saveCoverageXml();
$logger->info("[phpcoverage.remote.bottom.inc.php] Saved coverage xml",
__FILE__, __LINE__);
$cov->startInstrumentation();
$logger->info("[phpcoverage.remote.bottom.inc.php] Instrumentation turned on.",
__FILE__, __LINE__);
$object = serialize($cov);
file_put_contents($tmpFile, $object);
$logger->info("[phpcoverage.remote.bottom.inc.php] ################## END ###################",
__FILE__, __LINE__);
}
}
?>
<?php
/*
* $Id: phpcoverage.remote.top.inc.php 14666 2005-03-23 19:39:55Z npac $
*
* 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
if(isset($_REQUEST)){
$debug = false;
// Uncomment the line below to permanently turn on debugging.
// Alternatively, export a variable called phpcoverage-debug before
// starting the web server.
$debug = true;
if(isset($_REQUEST["phpcoverage-debug"]) ||
isset($_SERVER["phpcoverage-debug"]) ||
isset($_ENV["phpcoverage-debug"])) {
$debug = true;
}
if($debug) error_log("[phpcoverage.remote.top.inc.php] ################## START ###################");
$PHPCOVERAGE_HOME = false;
global $PHPCOVERAGE_HOME;
$basedir = dirname(__FILE__);
$this_script = basename(__FILE__);
$called_script = basename($_SERVER["SCRIPT_FILENAME"]);
if(!empty($_REQUEST["PHPCOVERAGE_HOME"])) {
$PHPCOVERAGE_HOME = $_REQUEST["PHPCOVERAGE_HOME"];
}
if(empty($PHPCOVERAGE_HOME)) {
$env_var = getenv("PHPCOVERAGE_HOME");
if(empty($env_var)) {
$msg = "Could not find PHPCOVERAGE_HOME. Please either export it in your environment before starting the web server. Or include PHPCOVERAGE_HOME=<path> in your HTTP request.";
error_log("[phpcoverage.remote.top.inc.php] FATAL: " . $msg);
die($msg);
}
else {
$PHPCOVERAGE_HOME = $env_var;
}
}
if(empty($PHPCOVERAGE_HOME) || !is_dir($PHPCOVERAGE_HOME)) {
$msg = "ERROR: Could not locate PHPCOVERAGE_HOME [$PHPCOVERAGE_HOME]. ";
$msg .= "Use 'php <filename> PHPCOVERAGE_HOME=/path/to/coverage/home'\n";
die($msg);
}
// Fallback
if(!defined("PHPCOVERAGE_HOME")) {
$include_path = get_include_path();
set_include_path($PHPCOVERAGE_HOME. ":" . $include_path);
define('PHPCOVERAGE_HOME', $PHPCOVERAGE_HOME);
}
if($debug) error_log("[phpcoverage.remote.top.inc.php] PHPCOVERAGE_HOME=" . $PHPCOVERAGE_HOME);
// Register the shutdown function to get code coverage results before
// script exits abnormally.
register_shutdown_function('spikephpcoverage_before_shutdown');
require_once PHPCOVERAGE_HOME . "/conf/phpcoverage.conf.php";
require_once PHPCOVERAGE_HOME . "/util/Utility.php";
require_once PHPCOVERAGE_HOME . "/remote/RemoteCoverageRecorder.php";
require_once PHPCOVERAGE_HOME . "/reporter/HtmlCoverageReporter.php";
global $util;
$logger = $util->getLogger();
// Create a distinct hash (may or may not be unique)
$session_id = md5($_SERVER["REMOTE_ADDR"] . $_SERVER["SERVER_NAME"]);
$tmpFile = $util->getTmpDir() . "/phpcoverage.session." . $session_id;
$logger->info("[phpcoverage.remote.top.inc.php] Session id: " . $session_id . " Saved in: " . $tmpFile,
__FILE__, __LINE__);
if(file_exists($tmpFile)) {
$object = file_get_contents($tmpFile);
$cov = unserialize($object);
$logger->info("[phpcoverage.remote.top.inc.php] Coverage object found." ,
__FILE__, __LINE__);
}
else {
$covReporter = new HtmlCoverageReporter(
"PHPCoverage report",
"",
$util->getTmpDir() . "/php-coverage-report"
);
$cov = new RemoteCoverageRecorder(array(), array(), $covReporter);
$object = serialize($cov);
file_put_contents($tmpFile, $object);
$logger->info("[phpcoverage.remote.top.inc.php] Stored coverage object found",
__FILE__, __LINE__);
}
if(!empty($_REQUEST["phpcoverage-action"])) {
$logger->info("[phpcoverage.remote.top.inc.php] phpcoverage-action=" . strtolower($_REQUEST["phpcoverage-action"]),
__FILE__, __LINE__);
switch(strtolower($_REQUEST["phpcoverage-action"])) {
case "init":
if(!empty($_REQUEST["tmp-dir"])) {
$cov->setTmpDir($_REQUEST["tmp-dir"]);
}
$cov->setCoverageFileName($_REQUEST["cov-file-name"]);
if(!$cov->cleanCoverageFile()) {
die("Cannot delete existing coverage data.");
}
break;
case "instrument":
break;
case "get-coverage-xml":
$cov->getCoverageXml();
break;
case "cleanup":
if(file_exists($tmpFile) && is_writable($tmpFile)) {
unlink($tmpFile);
unset($cov);
$logger->info("[phpcoverage.remote.top.inc.php] Cleaned up!",
__FILE__, __LINE__);
return;
}
else {
$logger->error("[phpcoverage.remote.top.inc.php] Error deleting file: " . $tmpFile,
__FILE__, __LINE__);
}
break;
}
}
$cov->startInstrumentation();
$logger->info("[phpcoverage.remote.top.inc.php] Instrumentation turned on.",
__FILE__, __LINE__);
$object = serialize($cov);
file_put_contents($tmpFile, $object);
$logger->info("[phpcoverage.remote.top.inc.php] BEGIN: " . $called_script,
__FILE__, __LINE__);
}
function spikephpcoverage_before_shutdown() {
global $cov, $logger;
$logger->debug("[phpcoverage.remote.top.inc.php::before_shutdown()] Getting code coverage before shutdown: START",
__FILE__, __LINE__);
require dirname(__FILE__) . "/phpcoverage.remote.bottom.inc.php";
$logger->debug("[phpcoverage.remote.top.inc.php::before_shutdown()] Getting code coverage before shutdown: FINISH",
__FILE__, __LINE__);
}
?>
This diff is collapsed.
<?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
/**
* Reader that parses Xdebug Trace data.
*
* @author Nimish Pachapurkar <npac@spikesource.com>
* @version $Revision: $
* @package SpikePHPCoverage_Parser
*/
class XdebugTraceReader {
/*{{{ Members */
protected $traceFilePath;
protected $handle;
protected $coverage = array();
/*}}}*/
/*{{{ Constructor */
/**
* Constructor
*
* @param $traceFilePath Path of the Xdebug trace file
* @access public
*/
public function __construct($traceFilePath) {
$this->traceFilePath = $traceFilePath;
}
/*}}}*/
/*{{{ protected function openTraceFile() */
/**
* Opens the trace file
*
* @return Boolean True on success, false on failure.
* @access protected
*/
protected function openTraceFile() {
$this->handle = fopen($this->traceFilePath, "r");
return !empty($this->handle);
}
/*}}}*/
/*{{{ public function parseTraceFile() */
/**
* Parses the trace file
*
* @return Boolean True on success, false on failure.
* @access public
*/
public function parseTraceFile() {
if(!$this->openTraceFile()) {
error_log("[XdebugTraceReader::parseTraceFile()] Unable to read trace file.");
return false;
}
while(!feof($this->handle)) {
$line = fgets($this->handle);
// echo "Line: " . $line . "\n";
$this->processTraceLine($line);
}
fclose($this->handle);
return true;
}
/*}}}*/
/*{{{ protected function processTraceLine() */
/**
* Process a give trace line
*
* @param $line Line from a trace file
* @return Boolean True on success, false on failure
* @access protected
*/
protected function processTraceLine($line) {
$dataparts = explode("\t", $line);
// print_r($dataparts);
$cnt = count($dataparts);
if($cnt < 2) {
return false;
}
if(!file_exists($dataparts[$cnt-2])) {
// echo "No file: " . $dataparts[$cnt-2] . "\n";
return false;
}
// Trim the entries
$dataparts[$cnt-2] = trim($dataparts[$cnt-2]);
$dataparts[$cnt-1] = trim($dataparts[$cnt-1]);
if(!isset($this->coverage[$dataparts[$cnt-2]][$dataparts[$cnt-1]])) {
$this->coverage[$dataparts[$cnt-2]][$dataparts[$cnt-1]] = 1;
}
else {
$this->coverage[$dataparts[$cnt-2]][$dataparts[$cnt-1]] ++;
}
return true;
}
/*}}}*/
/*{{{ public function getCoverageData() */
/**
* Returns the coverage array
*
* @return Array Array of coverage data from parsing.
* @access public
*/
public function getCoverageData() {
return $this->coverage;
}
/*}}}*/
}
?>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
</td></tr>
</table>
</div>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Spike PHPCoverage Details: %%filename%%</title>
<link href="%%style%%" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="pageBox" >
<table border="0" cellpadding="2" cellspacing="0" id="contentBox" width="100%">
<tr>
<td align="left" valign="top"><h1>Spike PHPCoverage Details: %%filename%%</h1>
</td>
</tr>
<tr>
<td>
<div id="footerBox">
<table width="800" border="0" cellspacing="0" cellpadding="0" >
<tr>
<td class="copyright" ><a class="footerlink" href="http://www.spikesource.com/projects/phpcoverage/" >Spike PHPCoverage Home</a></td>
<td class="copyright" align="right">&copy; 2004<script language="JavaScript" type="text/javascript">
var d=new Date();
yr=d.getFullYear();
if (yr!=2004) {
document.write("-"+yr);
}
</script>, SpikeSource, Inc.</td>
</tr>
</table>
<a href="mailto:ip@spikesource.com"><img src="images/spacer.gif" width="1" height="1" border="0" alt="spacer"/></a> </div>
</div>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>%%heading%%</title>
<link href="css/%%style%%" rel="stylesheet" type="text/css"/>
<script language="JavaScript" type="text/javascript" src="js/sort_spikesource.js"> </script>
<script language="JavaScript" type="text/javascript">
var tableSorter = null;
function initSorting() {
if (document.getElementById("table2sort")) {
tableSorter = new TableSorter(document.getElementById("table2sort"));
// initialize table
tableSorter.initTable();
// collapse all
collapseAll();
}
}
function sort(col, type) {
if (tableSorter != null) {
tableSorter.sort(col, type);
}
}
function toggleShowChildren(id) { tableSorter.togglechildren(id); }
function collapseAll() { tableSorter.collapseAllChildren(); }
function expandAll() { tableSorter.expandAllChildren(); }
</script>
</head>
<body onload="initSorting(); sort(5, 'percentage'); sort(5,'percentage');">
<div id="pageBox" >
<table id="navBox" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style=""><img align="bottom" name="logo" src="images/spikesource/phpcoverage.gif" alt="home" border="0" height="82" width="800"/></td>
</td>
</tr>
</table>
This diff is collapsed.
<?php
/*
* $Id: license.txt 13981 2005-03-16 08:09:28Z eespino $
*
* 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
class CoverageLogger {
private $level;
private $logLevels = array(
"LOG_CRITICAL",
"LOG_ERROR",
"LOG_WARNING",
"LOG_NOTICE",
"LOG_INFO",
"LOG_DEBUG"
);
public function setLevel($level) {
if(!is_numeric($level)) {
for($i = 0; $i < count($this->logLevels); $i++) {
if(strcasecmp($this->logLevels[$i], $level) === 0) {
$level = $i;
break;
}
}
}
$this->level = $level;
}
public function critical($str, $file="", $line="") {
if($this->level >= 0) {
error_log("[CRITICAL] [" . $file . ":" . $line . "] " . $str);
}
}
public function error($str, $file="", $line="") {
if($this->level >= 1) {
error_log("[ERROR] [" . $file . ":" . $line . "] " . $str);
}
}
public function warn($str, $file="", $line="") {
if($this->level >= 2) {
error_log("[WARNING] [" . $file . ":" . $line . "] " . $str);
}
}
public function notice($str, $file="", $line="") {
if($this->level >= 3) {
error_log("[NOTICE] [" . $file . ":" . $line . "] " . $str);
}
}
public function info($str, $file="", $line="") {
if($this->level >= 4) {
error_log("[INFO] [" . $file . ":" . $line . "] " . $str);
}
}
public function debug($str, $file="", $line="") {
if($this->level >= 5) {
error_log("[DEBUG] [" . $file . ":" . $line . "] " . $str);
}
}
public function getLevelName($level) {
return $this->logLevels[$level];
}
}
// testing
if(isset($_SERVER["argv"][1]) && $_SERVER["argv"][1] == "__main__") {
$logger = new CoverageLogger();
for($i = 0; $i < 6; $i++) {
$logger->setLevel($i);
error_log("############## Level now: " . $i);
$logger->debug("");
$logger->info("");
$logger->notice("");
$logger->warn("");
$logger->error("");
$logger->critical("");
}
error_log("############# With Level Names");
for($i = 0; $i < 6; $i++) {
$logger->setLevel($logger->getLevelName($i));
error_log("############## Level now: " . $logger->getLevelName($i));
$logger->debug("");
$logger->info("", __FILE__, __LINE__);
$logger->notice("");
$logger->warn("");
$logger->error("");
$logger->critical("");
}
}
?>
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment