Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/spikephpcoverage/src/CoverageRecorder.php
Go to the documentation of this file.
00001 <?php
00002     /*
00003     *  $Id: CoverageRecorder.php,v 1.2 2010/12/14 17:35:58 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(__FILE__));
00014     }
00015     require_once __PHPCOVERAGE_HOME . "/conf/phpcoverage.conf.php";
00016     require_once __PHPCOVERAGE_HOME . "/util/Utility.php";
00017     require_once __PHPCOVERAGE_HOME . "/reporter/CoverageReporter.php";
00018 
00037     class CoverageRecorder {
00038 
00039         // {{{ Members
00040 
00041         protected $includePaths;
00042         protected $excludePaths;
00043         protected $reporter;
00044         protected $coverageData;
00045         protected $isRemote = false;
00046         protected $stripped = false;
00047         protected $phpCoverageFiles = array("phpcoverage.inc.php");
00048         protected $version;
00049         protected $logger;
00050 
00056         protected $phpExtensions;
00057 
00058         // }}}
00059         // {{{ Constructor
00060 
00069         public function __construct(
00070             $includePaths=array("."),
00071             $excludePaths=array(), 
00072             $reporter="new HtmlCoverageReporter()"
00073         ) {
00074 
00075             $this->includePaths = $includePaths;
00076             $this->excludePaths = $excludePaths;
00077             $this->reporter = $reporter;
00078             // Set back reference
00079             $this->reporter->setCoverageRecorder($this);
00080             $this->excludeCoverageDir();
00081             $this->version = "0.8.2";
00082 
00083             // Configuration
00084             global $spc_config;
00085             $this->phpExtensions = $spc_config['extensions'];
00086             global $util;
00087             $this->logger = $util->getLogger();
00088         }
00089 
00090         // }}}
00091         // {{{ public function startInstrumentation()
00092 
00098         public function startInstrumentation() {
00099             if(extension_loaded("xdebug")) {
00100                 xdebug_start_code_coverage();
00101                 return true;
00102             }
00103             $this->logger->critical("[CoverageRecorder::startInstrumentation()] " 
00104             . "ERROR: Xdebug not loaded.", __FILE__, __LINE__);
00105             return false;
00106         }
00107 
00108         // }}}
00109         // {{{ public function stopInstrumentation()
00110 
00116         public function stopInstrumentation() {
00117             if(extension_loaded("xdebug")) {
00118                 $this->coverageData = xdebug_get_code_coverage();
00119                 xdebug_stop_code_coverage();
00120                 $this->logger->debug("[CoverageRecorder::stopInstrumentation()] Code coverage: " . print_r($this->coverageData, true),
00121                     __FILE__, __LINE__);
00122                 return true;
00123             }
00124             else {
00125                 $this->logger->critical("[CoverageRecorder::stopInstrumentation()] Xdebug not loaded.", __FILE__, __LINE__);
00126             }
00127             return false;
00128         }
00129 
00130         // }}}
00131         // {{{ public function generateReport()
00132 
00138         public function generateReport() {
00139             if($this->isRemote) {
00140                 $this->logger->info("[CoverageRecorder::generateReport()] "
00141                 ."Writing report.", __FILE__, __LINE__);
00142             }
00143             else {
00144                 $this->logger->info("[CoverageRecorder::generateReport()] "
00145                 . "Writing report:\t\t", __FILE__, __LINE__);
00146             }
00147             $this->logger->debug("[CoverageRecoder::generateReport()] " . print_r($this->coverageData, true),
00148                 __FILE__, __LINE__);
00149             $this->unixifyCoverageData();
00150             $this->coverageData = $this->stripCoverageData();
00151             $this->reporter->generateReport($this->coverageData);
00152             if($this->isRemote) {
00153                 $this->logger->info("[CoverageRecorder::generateReport()] [done]", __FILE__, __LINE__);
00154             }
00155             else {
00156                 $this->logger->info("[done]", __FILE__, __LINE__);
00157             }
00158         }
00159 
00160         // }}}
00161         /*{{{ protected function removeAbsentPaths() */
00162 
00169         protected function removeAbsentPaths(&$dirs) {
00170             for($i = 0; $i < count($dirs); $i++) {
00171                 if(! file_exists($dirs[$i])) {
00172                     // echo "Not found: " . $dirs[$i] . "\n";
00173                     $this->errors[] = "Not found: " . $dirs[$i] 
00174                     . ". Removing ...";
00175                     array_splice($dirs, $i, 1);
00176                     $i--;
00177                 }
00178                 else {
00179                     $dirs[$i] = realpath($dirs[$i]);
00180                 }
00181             }
00182         }
00183 
00184         /*}}}*/
00185         // {{{ protected function processSourcePaths()
00186 
00192         protected function processSourcePaths() {
00193             $this->removeAbsentPaths($this->includePaths);
00194             $this->removeAbsentPaths($this->excludePaths);
00195 
00196             sort($this->includePaths, SORT_STRING);
00197         }
00198 
00199         // }}}
00200         /*{{{ protected function getFilesAndDirs() */
00201 
00209         protected function getFilesAndDirs($dir, &$files) {
00210             global $util;
00211             $dirs[] = $dir;
00212             while(count($dirs) > 0) {
00213                 $currDir = realpath(array_pop($dirs));
00214                 if(!is_readable($currDir)) {
00215                     continue;
00216                 }
00217                 //echo "Current Dir: $currDir \n";
00218                 $currFiles = scandir($currDir);
00219                 //print_r($currFiles);
00220                 for($j = 0; $j < count($currFiles); $j++) {
00221                     if($currFiles[$j] == "." || $currFiles[$j] == "..") {
00222                         continue;
00223                     }
00224                     $currFiles[$j] = $currDir . "/" . $currFiles[$j];
00225                     //echo "Current File: " . $currFiles[$j] . "\n";
00226                     if(is_file($currFiles[$j])) {
00227                         $pathParts = pathinfo($currFiles[$j]);
00228                         if(isset($pathParts['extension']) && in_array($pathParts['extension'], $this->phpExtensions)) {
00229                             $files[] = $util->replaceBackslashes($currFiles[$j]);
00230                         }
00231                     }
00232                     if(is_dir($currFiles[$j])) {
00233                         $dirs[] = $currFiles[$j];
00234                     }
00235                 }
00236             }
00237         }
00238 
00239         /*}}}*/
00240         /*{{{ protected function addFiles() */
00241 
00247         protected function addFiles() {
00248             global $util;
00249             $files = array();
00250             for($i = 0; $i < count($this->includePaths); $i++) {
00251                 $this->includePaths[$i] = $util->replaceBackslashes($this->includePaths[$i]);
00252                 if(is_dir($this->includePaths[$i])) {
00253                     //echo "Calling getFilesAndDirs with " . $this->includePaths[$i] . "\n";
00254                     $this->getFilesAndDirs($this->includePaths[$i], $files);
00255                 }
00256                 else if(is_file($this->includePaths[$i])) {
00257                     $files[] = $this->includePaths[$i];
00258                 }
00259             }
00260 
00261             $this->logger->debug("Found files:" . print_r($files, true),
00262                 __FILE__, __LINE__);
00263             for($i = 0; $i < count($this->excludePaths); $i++) {
00264                 $this->excludePaths[$i] = $util->replaceBackslashes($this->excludePaths[$i]);
00265             }
00266 
00267             for($i = 0; $i < count($files); $i++) {
00268                 for($j = 0; $j < count($this->excludePaths); $j++) {
00269                     $this->logger->debug($files[$i] . "\t" . $this->excludePaths[$j] . "\n", __FILE__, __LINE__);
00270                     if(strpos($files[$i], $this->excludePaths[$j]) === 0) {
00271                         continue;
00272                     }
00273                 }
00274                 if(!array_key_exists($files[$i], $this->coverageData)) {
00275                     $this->coverageData[$files[$i]] =  array();
00276                 }
00277             }
00278         }
00279 
00280         /*}}}*/
00281         // {{{ protected function stripCoverageData()
00282 
00289         protected function stripCoverageData() {
00290             if($this->stripped) {
00291                 $this->logger->debug("[CoverageRecorder::stripCoverageData()] Already stripped!", __FILE__, __LINE__);
00292                 return $this->coverageData;
00293             }
00294             $this->stripped = true;
00295             if(empty($this->coverageData)) {
00296                 $this->logger->warn("[CoverageRecorder::stripCoverageData()] No coverage data found.", __FILE__, __LINE__);
00297                 return $this->coverageData;
00298             }
00299             $this->processSourcePaths();
00300             $this->logger->debug("!!!!!!!!!!!!! Source Paths !!!!!!!!!!!!!!",
00301                 __FILE__, __LINE__);
00302             $this->logger->debug(print_r($this->includePaths, true),
00303                 __FILE__, __LINE__);
00304             $this->logger->debug(print_r($this->excludePaths, true),
00305                 __FILE__, __LINE__);
00306             $this->logger->debug("!!!!!!!!!!!!! Source Paths !!!!!!!!!!!!!!",
00307                 __FILE__, __LINE__);
00308             $this->addFiles();
00309             $altCoverageData = array();
00310             foreach ($this->coverageData as $filename => &$lines) {
00311                 $preserve = false;
00312                 $realFile = $filename;
00313                 for($i = 0; $i < count($this->includePaths); $i++) {
00314                     if(strpos($realFile, $this->includePaths[$i]) === 0) {
00315                         $preserve = true;
00316                     }
00317                     else {
00318                         $this->logger->debug("File: " . $realFile 
00319                         . "\nDoes not match: " . $this->includePaths[$i],
00320                         __FILE__, __LINE__);
00321                     }
00322                 }
00323                 // Exclude dirs have a precedence over includes.
00324                 for($i = 0; $i < count($this->excludePaths); $i++) {
00325                     if(strpos($realFile, $this->excludePaths[$i]) === 0) {
00326                         $preserve = false;
00327                     }
00328                     else if(in_array(basename($realFile), $this->phpCoverageFiles)) {
00329                         $preserve = false;
00330                     }
00331                 }
00332                 if($preserve) {
00333                     // Should be preserved
00334                     $altCoverageData[$filename] = $lines;
00335                 }
00336 
00337                 // Fix for bug #34 <http://developer.spikesource.com/tracker/index.php?func=detail&aid=34&group_id=9&atid=117>
00338                 // Finally get rid of data for extensions we don't care about
00339                 if (is_file($filename)) {
00340                     $parts = pathinfo($filename);
00341                     if (!empty($parts['extension']) && !in_array($parts['extension'], $this->phpExtensions)) {
00342                         // Remove this key and its contents
00343                         if (isset($altCoverageData[$filename])) {
00344                             $this->logger->debug("!!! Extension mismatch; Removing file: " . $filename, __FILE__, __LINE__);
00345                             unset($altCoverageData[$filename]);
00346                         }
00347                     }
00348                 }
00349             }
00350 
00351             array_multisort($altCoverageData, SORT_STRING);
00352             return $altCoverageData;
00353         }
00354 
00355         // }}}
00356         /*{{{ protected function unixifyCoverageData() */
00357 
00364         protected function unixifyCoverageData() {
00365             global $util;
00366             $tmpCoverageData = array();
00367             foreach($this->coverageData as $file => &$lines) {
00368                 $tmpCoverageData[$util->replaceBackslashes(realpath($file))] = $lines;
00369             }
00370             $this->coverageData = $tmpCoverageData;
00371         }
00372 
00373         /*}}}*/
00374         // {{{ public function getErrors()
00375 
00382         public function getErrors() {
00383             return $this->errors;
00384         }
00385 
00386         // }}}
00387         // {{{ public function logErrors()
00388 
00394         public function logErrors() {
00395             $this->logger->error(print_r($this->errors, true),
00396                 __FILE__, __LINE__);
00397         }
00398 
00399         // }}}
00400         /*{{{ Getters and Setters */
00401 
00402         public function getIncludePaths() {
00403             return $this->includePaths;
00404         }
00405 
00406         public function setIncludePaths($includePaths) {
00407             $this->includePaths = $includePaths;
00408         }
00409 
00410         public function getExcludePaths() {
00411             return $this->excludePaths;
00412         }
00413 
00414         public function setExcludePaths($excludePaths) {
00415             $this->excludePaths = $excludePaths;
00416             $this->excludeCoverageDir();
00417         }
00418 
00419         public function getReporter() {
00420             return $this->reporter;
00421         }
00422 
00423         public function setReporter(&$reporter) {
00424             $this->reporter = $reporter;
00425         }
00426 
00427         public function getPhpExtensions() {
00428             return $this->phpExtensions;
00429         }
00430 
00431         public function setPhpExtensions(&$extensions) {
00432             $this->phpExtensions = $extensions;
00433         }
00434 
00435         public function getVersion() {
00436             return $this->version;
00437         }
00438 
00439         /*}}}*/
00440         /*{{{ public function excludeCoverageDir() */
00441 
00447         public function excludeCoverageDir() {
00448             $f = __FILE__;
00449             if(is_link($f)) {
00450                 $f = readlink($f);
00451             }
00452             $this->excludePaths[] = realpath(dirname($f));
00453         }
00454         /*}}}*/
00455     }
00456 ?>
 All Data Structures Namespaces Files Functions Variables Enumerations