MDL-19579 code coverage - add Spike PHPCoverage lib (LGPL)
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
<?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 <[email protected]>
|
||||
* @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;
|
||||
}
|
||||
|
||||
/*}}}*/
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,92 @@
|
||||
<?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 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 <[email protected]>
|
||||
* @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;
|
||||
}
|
||||
|
||||
/*}}}*/
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,476 @@
|
||||
<?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
|
||||
|
||||
if(!defined("__PHPCOVERAGE_HOME")) {
|
||||
define("__PHPCOVERAGE_HOME", dirname(dirname(__FILE__)));
|
||||
}
|
||||
require_once __PHPCOVERAGE_HOME . "/parser/Parser.php";
|
||||
|
||||
/**
|
||||
* Parser for PHP files
|
||||
*
|
||||
* @author Nimish Pachapurkar ([email protected])
|
||||
* @version $Revision$
|
||||
* @package SpikePHPCoverage_Parser
|
||||
*/
|
||||
class PHPParser extends Parser {
|
||||
/*{{{ Members */
|
||||
|
||||
private $inHereDoc = false;
|
||||
private $inFunction = false;
|
||||
private $phpStarters = array('<?php', '<?', '<?=');
|
||||
private $phpFinisher = '?>';
|
||||
private $inComment = false;
|
||||
private $lastLineEndTokenType = "";
|
||||
private $fileToken = null;
|
||||
private $currFileToken = 0;
|
||||
private $lineNb = 0;
|
||||
private $multiLineTok = null;
|
||||
// If one of these tokens occur as the last token of a line
|
||||
// then the next line can be treated as a continuation line
|
||||
// depending on how it starts.
|
||||
public static $contTypes = array(
|
||||
"(",
|
||||
",",
|
||||
".",
|
||||
"=",
|
||||
T_LOGICAL_XOR,
|
||||
T_LOGICAL_AND,
|
||||
T_LOGICAL_OR,
|
||||
T_PLUS_EQUAL,
|
||||
T_MINUS_EQUAL,
|
||||
T_MUL_EQUAL,
|
||||
T_DIV_EQUAL,
|
||||
T_CONCAT_EQUAL,
|
||||
T_MOD_EQUAL,
|
||||
T_AND_EQUAL,
|
||||
T_OR_EQUAL,
|
||||
T_XOR_EQUAL,
|
||||
T_BOOLEAN_AND,
|
||||
T_BOOLEAN_OR,
|
||||
T_OBJECT_OPERATOR,
|
||||
T_DOUBLE_ARROW,
|
||||
"[",
|
||||
"]",
|
||||
T_LOGICAL_OR,
|
||||
T_LOGICAL_XOR,
|
||||
T_LOGICAL_AND,
|
||||
T_STRING
|
||||
);
|
||||
/*}}}*/
|
||||
|
||||
/*{{{ protected function openFileReadOnly() */
|
||||
|
||||
/**
|
||||
* Opens the file to be parsed in Read-only mode.
|
||||
* Overriden to tokenize the whole file.
|
||||
*
|
||||
* @return FALSE on failure.
|
||||
* @access protected
|
||||
*/
|
||||
protected function openFileReadOnly() {
|
||||
$this->fileToken = @token_get_all(file_get_contents($this->filename));
|
||||
return parent::openFileReadOnly();
|
||||
}
|
||||
|
||||
/*}}}*/
|
||||
/*{{{ protected function getNextToken() */
|
||||
|
||||
/**
|
||||
* Gets the next token.
|
||||
*
|
||||
* The same token can be returned several times for multi-line
|
||||
* tokens.
|
||||
*
|
||||
* @param $line The current line read from the file.
|
||||
* @param &$pos The position of the next token string in the line.
|
||||
* @return the next token or null at the end of the line.
|
||||
* @access protected
|
||||
*/
|
||||
protected function getNextToken($line, &$pos) {
|
||||
$lineLen = strlen($line);
|
||||
if($pos >= $lineLen) {
|
||||
return null;
|
||||
}
|
||||
if($this->multiLineTok != null) {
|
||||
list($tok, $lnb, $posnl) = $this->multiLineTok;
|
||||
if(is_string($tok)) {
|
||||
$str = $tok;
|
||||
} else {
|
||||
$str = $tok[1];
|
||||
}
|
||||
if($posnl >= strlen($str)) {
|
||||
$this->multiLineTok = null;
|
||||
} else {
|
||||
if(substr($str, $posnl + 1, $lineLen) == $line) {
|
||||
$pos += $lineLen;
|
||||
$newPosnl = $posnl + $lineLen;
|
||||
} else {
|
||||
$newPosnl = strpos($str, "\n", $posnl + 1);
|
||||
if($newPosnl === false) {
|
||||
$newPosnl = strlen($str);
|
||||
}
|
||||
$len = $newPosnl - $posnl - 1;
|
||||
//if(substr($str, $posnl + 1, $len) != substr($line, $pos, $len)) {
|
||||
//}
|
||||
$pos += $len;
|
||||
}
|
||||
$this->multiLineTok[1]++;
|
||||
$this->multiLineTok[2] = $newPosnl;
|
||||
return $tok;
|
||||
}
|
||||
}
|
||||
if(!isset($this->fileToken[$this->currFileToken])) {
|
||||
return null;
|
||||
}
|
||||
$tok = &$this->fileToken[$this->currFileToken];
|
||||
if(is_string($tok)) {
|
||||
$str = $tok;
|
||||
} else {
|
||||
$str = $tok[1];
|
||||
}
|
||||
$nbnl = substr_count($str, "\n");
|
||||
if($nbnl > 0 && ($posnl = strpos($str, "\n")) != strlen($str) - 1) {
|
||||
$this->multiLineTok = array($tok, 1, $posnl);
|
||||
$str = substr($str, 0, $posnl + 1);
|
||||
}
|
||||
if(substr($line, $pos, strlen($str)) == $str) {
|
||||
$this->currFileToken++;
|
||||
$pos += strlen($str);
|
||||
return $tok;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*}}}*/
|
||||
/*{{{ protected function isMultiLineCont() */
|
||||
|
||||
/**
|
||||
* Determines if the beginning of current line is a
|
||||
* continuation of an executable multi-line token.
|
||||
*
|
||||
* Called at the first token of a line.
|
||||
*
|
||||
* @return Boolean true if it is a continuation line
|
||||
* @access protected
|
||||
*/
|
||||
protected function isMultiLineCont() {
|
||||
if($this->multiLineTok == null
|
||||
|| $this->multiLineTok[1] <= 1) {
|
||||
return false;
|
||||
}
|
||||
switch ($this->getTokenType($this->multiLineTok[0])) {
|
||||
case T_COMMENT:
|
||||
case T_INLINE_HTML: // <br/><b>jhsk</b>
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*}}}*/
|
||||
/*{{{ protected function processLine() */
|
||||
|
||||
/**
|
||||
* Process a line read from the file and determine if it is an
|
||||
* executable line or not.
|
||||
*
|
||||
* This is the work horse function that does most of the parsing.
|
||||
* To parse PHP, get_all_tokens() tokenizer function is used.
|
||||
*
|
||||
* @param $line Line to be parsed.
|
||||
* @access protected
|
||||
*/
|
||||
protected function processLine($line) {
|
||||
|
||||
// Default values
|
||||
$prevLineType = $this->lineType;
|
||||
$this->lineType = LINE_TYPE_NOEXEC;
|
||||
$tokenCnt = 0;
|
||||
$this->lineNb++;
|
||||
$pos = 0;
|
||||
$seeMore = false;
|
||||
$seenEnough = false;
|
||||
$lastToken = null;
|
||||
|
||||
while (($token = $this->getNextToken($line, $pos))) {
|
||||
if (!is_string($token)) {
|
||||
$stoken = token_name($token[0]) . ' "'
|
||||
. str_replace(array("\\", "\"", "\n", "\r")
|
||||
, array("\\\\", "\\\"", "\\n", "\\r")
|
||||
, $token[1]) . '"';
|
||||
if (isset($token[2])) {
|
||||
$stoken .= '[' . $token[2] . ']';
|
||||
if ($token[2] != $this->lineNb) {
|
||||
$stoken .= ' != [' . $this->lineNb . ']';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$stoken = $token;
|
||||
}
|
||||
$this->logger->debug("Token $stoken", __FILE__, __LINE__);
|
||||
if (!is_string($token) && $token[0] == T_WHITESPACE) {
|
||||
continue;
|
||||
}
|
||||
$lastToken = $token;
|
||||
$tokenCnt ++;
|
||||
if ($this->inHereDoc) {
|
||||
$this->lineType = LINE_TYPE_CONT;
|
||||
$this->logger->debug("Here doc Continuation! Token: $token",
|
||||
__FILE__, __LINE__);
|
||||
|
||||
if ($this->getTokenType($token) == T_END_HEREDOC) {
|
||||
$this->inHereDoc = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($this->inFunction) {
|
||||
$this->lineType = LINE_TYPE_NOEXEC;
|
||||
$this->logger->debug("Function! Token: $token",
|
||||
__FILE__, __LINE__);
|
||||
if ($this->getTokenType($token) == '{') {
|
||||
$this->inFunction = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if($tokenCnt == 1 && $prevLineType != LINE_TYPE_NOEXEC
|
||||
&& ($this->isMultiLineCont()
|
||||
|| $this->isContinuation($token))) {
|
||||
$this->lineType = LINE_TYPE_CONT;
|
||||
$this->logger->debug("Continuation! Token: ".print_r($token, true),
|
||||
__FILE__, __LINE__);
|
||||
$seenEnough = true;
|
||||
continue;
|
||||
}
|
||||
if ($seenEnough) {
|
||||
continue;
|
||||
}
|
||||
if(is_string($token)) {
|
||||
// FIXME: Add more cases, if needed
|
||||
switch($token) {
|
||||
// Any of these things, are non-executable.
|
||||
// And so do not change the status of the line
|
||||
case '{':
|
||||
case '}':
|
||||
case '(':
|
||||
case ')':
|
||||
case ';':
|
||||
break;
|
||||
|
||||
// Everything else by default is executable.
|
||||
default:
|
||||
$this->logger->debug("Other string: $token",
|
||||
__FILE__, __LINE__);
|
||||
if($this->lineType == LINE_TYPE_NOEXEC) {
|
||||
$this->lineType = LINE_TYPE_EXEC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$this->logger->debug("Status: " . $this->getLineTypeStr($this->lineType) . "\t\tToken: $token",
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
else {
|
||||
// The token is an array
|
||||
list($tokenType, $text) = $token;
|
||||
switch($tokenType) {
|
||||
case T_COMMENT:
|
||||
case T_DOC_COMMENT:
|
||||
case T_WHITESPACE: // white space
|
||||
case T_OPEN_TAG: // < ?
|
||||
case T_OPEN_TAG_WITH_ECHO: // < ? =
|
||||
case T_CURLY_OPEN: //
|
||||
case T_INLINE_HTML: // <br/><b>jhsk</b>
|
||||
//case T_STRING: //
|
||||
case T_EXTENDS: // extends
|
||||
case T_STATIC: // static
|
||||
case T_STRING_VARNAME: // string varname?
|
||||
case T_CHARACTER: // character
|
||||
case T_ELSE: // else
|
||||
case T_CONSTANT_ENCAPSED_STRING: // "some str"
|
||||
case T_ARRAY: // array
|
||||
// Any of these things, are non-executable.
|
||||
// And so do not change the status of the line
|
||||
// as the line starts as non-executable.
|
||||
break;
|
||||
case T_START_HEREDOC:
|
||||
$this->inHereDoc = true;
|
||||
break;
|
||||
case T_PRIVATE: // private
|
||||
case T_PUBLIC: // public
|
||||
case T_PROTECTED: // protected
|
||||
case T_VAR: // var
|
||||
case T_GLOBAL: // global
|
||||
case T_CLASS: // class
|
||||
case T_INTERFACE: // interface
|
||||
case T_REQUIRE: // require
|
||||
case T_REQUIRE_ONCE: // require_once
|
||||
case T_INCLUDE: // include
|
||||
case T_INCLUDE_ONCE: // include_once
|
||||
case T_SWITCH: // switch
|
||||
case T_CONST: // const
|
||||
case T_TRY: // try
|
||||
$this->lineType = LINE_TYPE_NOEXEC;
|
||||
// No need to see any further
|
||||
$seenEnough = true;
|
||||
break;
|
||||
case T_FUNCTION: // function
|
||||
$this->lineType = LINE_TYPE_NOEXEC;
|
||||
$this->inFunction = true;
|
||||
// No need to see any further
|
||||
$seenEnough = true;
|
||||
break;
|
||||
case T_VARIABLE: // $foo
|
||||
$seeMore = true;
|
||||
if($this->lineType == LINE_TYPE_NOEXEC) {
|
||||
$this->lineType = LINE_TYPE_EXEC;
|
||||
}
|
||||
break;
|
||||
case T_CLOSE_TAG:
|
||||
if($this->lineType != LINE_TYPE_EXEC) {
|
||||
$this->lineType = LINE_TYPE_NOEXEC;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$this->logger->debug("Other token: " . token_name($tokenType),
|
||||
__FILE__, __LINE__);
|
||||
$seeMore = false;
|
||||
if($this->lineType == LINE_TYPE_NOEXEC) {
|
||||
$this->lineType = LINE_TYPE_EXEC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$this->logger->debug("Status: " . $this->getLineTypeStr($this->lineType) . "\t\tToken type: $tokenType \tText: $text",
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
if(($this->lineType == LINE_TYPE_EXEC && !$seeMore)
|
||||
|| $seenEnough) {
|
||||
// start moodle modification: comment debug line causing notices
|
||||
//$this->logger->debug("Made a decision! Exiting. Token Type: $tokenType & Text: $text",
|
||||
// __FILE__, __LINE__);
|
||||
// end moodle modification
|
||||
if($seenEnough) {
|
||||
$this->logger->debug("Seen enough at Token Type: $tokenType & Text: $text",
|
||||
__FILE__, __LINE__);
|
||||
} else {
|
||||
$seenEnough = true;
|
||||
}
|
||||
}
|
||||
} // end while
|
||||
$this->logger->debug("Line Type: " . $this->getLineTypeStr($this->lineType),
|
||||
__FILE__, __LINE__);
|
||||
$this->lastLineEndTokenType = $this->getTokenType($lastToken);
|
||||
$this->logger->debug("Last End Token: " . $this->lastLineEndTokenType,
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/*}}}*/
|
||||
/*{{{ public function getLineType() */
|
||||
|
||||
/**
|
||||
* Returns the type of line just read
|
||||
*
|
||||
* @return Line type
|
||||
* @access public
|
||||
*/
|
||||
public function getLineType() {
|
||||
return $this->lineType;
|
||||
}
|
||||
/*}}}*/
|
||||
/*{{{ protected function isContinuation() */
|
||||
|
||||
/**
|
||||
* Check if a line is a continuation of the previous line
|
||||
*
|
||||
* @param &$token Second token in a line (after PHP start)
|
||||
* @return Boolean True if the line is a continuation; false otherwise
|
||||
* @access protected
|
||||
*/
|
||||
protected function isContinuation(&$token) {
|
||||
if(is_string($token)) {
|
||||
switch($token) {
|
||||
case ".":
|
||||
case ",";
|
||||
case "]":
|
||||
case "[":
|
||||
case "(":
|
||||
case ")":
|
||||
case "=":
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
list($tokenType, $text) = $token;
|
||||
switch($tokenType) {
|
||||
case T_CONSTANT_ENCAPSED_STRING:
|
||||
case T_ARRAY:
|
||||
case T_DOUBLE_ARROW:
|
||||
case T_OBJECT_OPERATOR:
|
||||
case T_LOGICAL_XOR:
|
||||
case T_LOGICAL_AND:
|
||||
case T_LOGICAL_OR:
|
||||
case T_PLUS_EQUAL:
|
||||
case T_MINUS_EQUAL:
|
||||
case T_MUL_EQUAL:
|
||||
case T_DIV_EQUAL:
|
||||
case T_CONCAT_EQUAL:
|
||||
case T_MOD_EQUAL:
|
||||
case T_AND_EQUAL:
|
||||
case T_OR_EQUAL:
|
||||
case T_XOR_EQUAL:
|
||||
case T_BOOLEAN_AND:
|
||||
case T_BOOLEAN_OR:
|
||||
case T_LNUMBER:
|
||||
case T_DNUMBER:
|
||||
return true;
|
||||
|
||||
case T_STRING:
|
||||
case T_VARIABLE:
|
||||
return in_array($this->lastLineEndTokenType, PHPParser::$contTypes);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/*}}}*/
|
||||
/*{{{ protected function getTokenType() */
|
||||
|
||||
/**
|
||||
* Get the token type of a token (if exists) or
|
||||
* the token itself.
|
||||
*
|
||||
* @param $token Token
|
||||
* @return Token type or token itself
|
||||
* @access protected
|
||||
*/
|
||||
protected function getTokenType($token) {
|
||||
if(is_string($token)) {
|
||||
return $token;
|
||||
}
|
||||
else {
|
||||
list($tokenType, $text) = $token;
|
||||
return $tokenType;
|
||||
}
|
||||
}
|
||||
/*}}}*/
|
||||
/*
|
||||
// Main
|
||||
$obj = new PHPParser();
|
||||
$obj->parse("test.php");
|
||||
while(($line = $obj->getLine()) !== false) {
|
||||
echo "#########################\n";
|
||||
echo "[" . $line . "] Type: [" . $obj->getLineTypeStr($obj->getLineType()) . "]\n";
|
||||
echo "#########################\n";
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,217 @@
|
||||
<?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
|
||||
|
||||
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 ([email protected])
|
||||
* @version $Revision$
|
||||
* @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;
|
||||
}
|
||||
|
||||
/*}}}*/
|
||||
}
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user