|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 /* 00003 * $Id: RemoteCoverageRecorder.php,v 1.2 2010/12/14 17:36:05 moodlerobot Exp $ 00004 * 00005 * Copyright(c) 2004-2006, SpikeSource Inc. All Rights Reserved. 00006 * Licensed under the Open Software License version 2.1 00007 * (See http://www.spikesource.com/license.html) 00008 */ 00009 ?> 00010 <?php 00011 00012 if(!defined("__PHPCOVERAGE_HOME")) { 00013 define("__PHPCOVERAGE_HOME", dirname(dirname(__FILE__))); 00014 } 00015 require_once __PHPCOVERAGE_HOME . "/util/Utility.php"; 00016 require_once __PHPCOVERAGE_HOME . "/CoverageRecorder.php"; 00017 require_once __PHPCOVERAGE_HOME . "/remote/XdebugTraceReader.php"; 00018 require_once __PHPCOVERAGE_HOME . "/parser/CoverageXmlParser.php"; 00019 00027 class RemoteCoverageRecorder extends CoverageRecorder { 00028 /*{{{ Members */ 00029 00030 protected $traceFilePath; 00031 protected $xdebugTraceReader; 00032 protected $tmpDir; 00033 protected $tmpTraceFilename = "phpcoverage.xdebug.trace"; 00034 protected $coverageFileName = "phpcoverage.coverage.xml"; 00035 00036 protected $xmlStart = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><spike-phpcoverage>"; 00037 protected $xmlEnd = "</spike-phpcoverage>"; 00038 00039 /*}}}*/ 00040 /*{{{ public function __construct() */ 00041 00047 public function __construct( 00048 $includePaths=array("."), 00049 $excludePaths=array(), 00050 $reporter="new HtmlCoverageReporter()" 00051 ) { 00052 global $util; 00053 parent::__construct($includePaths, $excludePaths, $reporter); 00054 $this->isRemote = true; 00055 $this->phpCoverageFiles[] = "phpcoverage.remote.inc.php"; 00056 $this->phpCoverageFiles[] = "phpcoverage.remote.top.inc.php"; 00057 $this->phpCoverageFiles[] = "phpcoverage.remote.bottom.inc.php"; 00058 00059 // configuration 00060 $this->tmpDir = $util->getTmpDir(); 00061 } 00062 00063 /*}}}*/ 00064 /*{{{ Getters and Setters */ 00065 00066 public function getTraceFilePath() { 00067 return $this->traceFilePath; 00068 } 00069 00070 public function setTraceFilePath($traceFilePath) { 00071 $this->traceFilePath = $traceFilePath; 00072 } 00073 00074 public function getTmpDir() { 00075 return $this->tmpDir; 00076 } 00077 00078 public function setTmpDir($tmpTraceDir) { 00079 $this->tmpDir = $tmpTraceDir; 00080 } 00081 00082 public function getCoverageFileName() { 00083 return $this->coverageFileName; 00084 } 00085 00086 public function setCoverageFileName($covFileName) { 00087 $this->coverageFileName = $covFileName; 00088 } 00089 00090 /*}}}*/ 00091 /*{{{ public function cleanCoverageFile() */ 00092 00099 public function cleanCoverageFile() { 00100 $filepath = $this->tmpDir . "/" . $this->coverageFileName; 00101 if(file_exists($filepath)) { 00102 if(is_writable($filepath)) { 00103 unlink($filepath); 00104 } 00105 else { 00106 $this->logger->error("[RemoteCoverageRecorder::cleanCoverageFile()] " 00107 . "ERROR: Cannot delete $filepath.", __FILE__, __LINE__); 00108 return false; 00109 } 00110 } 00111 return true; 00112 } 00113 00114 /*}}}*/ 00115 /*{{{ protected function prepareCoverageXml() */ 00116 00123 protected function prepareCoverageXml() { 00124 global $util; 00125 $xmlString = ""; 00126 $xmlBody = ""; 00127 if(!empty($this->coverageData)) { 00128 foreach($this->coverageData as $file => &$lines) { 00129 $xmlBody .= "<file path=\"". $util->replaceBackslashes($file) . "\">"; 00130 foreach($lines as $linenum => &$frequency) { 00131 $xmlBody .= "<line line-number=\"" . $linenum . "\""; 00132 $xmlBody .= " frequency=\"" . $frequency . "\"/>"; 00133 } 00134 $xmlBody .= "</file>\n"; 00135 } 00136 unset($this->coverageData); 00137 } 00138 else { 00139 $this->logger->info("[RemoteCoverageRecorder::prepareCoverageXml()] Coverage data is empty.", 00140 __FILE__, __LINE__); 00141 } 00142 $xmlString .= $xmlBody; 00143 $this->logger->debug("[RemoteCoverageRecorder::prepareCoverageXml()] Xml: " . $xmlString, __FILE__, __LINE__); 00144 return $xmlString; 00145 } 00146 00147 /*}}}*/ 00148 /*{{{ protected function parseCoverageXml() */ 00149 00158 protected function parseCoverageXml(&$xml, $stream=false) { 00159 // Need to handle multiple xml files. 00160 if(!is_array($xml)) { 00161 $xml = array($xml); 00162 } 00163 for($i = 0; $i < count($xml); $i++) { 00164 $xmlParser = new CoverageXmlParser(); 00165 if($stream) { 00166 $xmlParser->setInput($xml[$i]); 00167 } 00168 else { 00169 $xmlParser->setInputString($xml[$i]); 00170 } 00171 $xmlParser->parse(); 00172 $data =& $xmlParser->getCoverageData(); 00173 if(empty($this->coverageData)) { 00174 $this->coverageData = $data; 00175 } 00176 else { 00177 $data2 = array_merge_recursive($this->coverageData, $data); 00178 $this->coverageData = $data2; 00179 } 00180 $this->logger->debug("[RemoteCoverageRecorder::prepareCoverageXml()] " . "Coverage data intermediate: " . print_r($this->coverageData, true)); 00181 } 00182 } 00183 00184 /*}}}*/ 00185 /*{{{ public function getCoverageXml() */ 00186 00192 public function getCoverageXml() { 00193 $filepath = $this->tmpDir . "/" . $this->coverageFileName; 00194 if(file_exists($filepath) && is_readable($filepath)) { 00195 $fp = fopen($filepath, "r"); 00196 if($fp) { 00197 while(!feof($fp)) { 00198 $xml = fread($fp, 4096); 00199 echo $xml; 00200 } 00201 fclose($fp); 00202 return true; 00203 } 00204 else { 00205 $this->logger->error("Could not read coverage data file.", 00206 __FILE__, __LINE__); 00207 } 00208 } 00209 else { 00210 $this->logger->error("[RemoteCoverageRecorder::getCoverageXml()] " 00211 . "ERROR: Cannot read file " . $filepath, __FILE__, __LINE__); 00212 } 00213 return false; 00214 } 00215 00216 /*}}} */ 00217 /*{{{ protected function appendDataToFile() */ 00218 00226 protected function appendDataToFile($newXml) { 00227 $filepath = $this->tmpDir . "/" . $this->coverageFileName; 00228 if(!file_exists($filepath)) { 00229 // If new file, write the xml start and end tags 00230 $bytes = file_put_contents($filepath, $this->xmlStart . "\n" . $this->xmlEnd); 00231 if(!$bytes) { 00232 $this->logger->critical("[RemoteCoverageRecorder::appendDataToFile()] Could not create file: " . $filepath, __FILE__, __LINE__); 00233 return false; 00234 } 00235 } 00236 if(file_exists($filepath) && is_readable($filepath)) { 00237 $res = fopen($filepath, "r+"); 00238 if($res) { 00239 fseek($res, -1 * strlen($this->xmlEnd), SEEK_END); 00240 $ret = fwrite($res, $newXml); 00241 if(!$ret) { 00242 $this->logger->error("[RemoteCoverageRecorder::appendDataToFile()] Could not append data to file.", 00243 __FILE__, __LINE__); 00244 fclose($res); 00245 return false; 00246 } 00247 fwrite($res, $this->xmlEnd); 00248 fclose($res); 00249 } 00250 else { 00251 $this->logger->error("[RemoteCoverageRecorder::appendDataToFile()] Error opening file for writing: " . $filepath, 00252 __FILE__, __LINE__); 00253 return false; 00254 } 00255 } 00256 return true; 00257 } 00258 00259 /*}}}*/ 00260 /*{{{ public function saveCoverageXml() */ 00261 00268 public function saveCoverageXml() { 00269 $filepath = $this->tmpDir . "/" . $this->coverageFileName; 00270 if($this->stopInstrumentation()) { 00271 $xml = $this->prepareCoverageXml(); 00272 $ret = $this->appendDataToFile($xml); 00273 if(!$ret) { 00274 $this->logger->warn("[RemoteCoverageRecorder::saveCoverageXml()] " 00275 . "ERROR: Nothing was written to " . $filepath, 00276 __FILE__, __LINE__); 00277 return false; 00278 } 00279 $this->logger->info("[RemoteCoverageRecorder::saveCoverageXml()] " 00280 . "Saved XML to $filepath; size: [" . filesize($filepath) 00281 . "]", __FILE__, __LINE__); 00282 return true; 00283 } 00284 return false; 00285 } 00286 00287 /*}}}*/ 00288 /*{{{ public function generateReport() */ 00289 00300 public function generateReport($xmlUrl, $stream=false) { 00301 $this->logger->debug("XML Url: " . $xmlUrl, __FILE__, __LINE__); 00302 $this->parseCoverageXml($xmlUrl, true); 00303 $this->logger->debug("Coverage Data final: " . print_r($this->coverageData, true)); 00304 parent::generateReport(); 00305 } 00306 00307 /*}}}*/ 00308 } 00309 ?>