123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- <?php
- /*
- * This file is part of the Lime framework.
- *
- * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
- * (c) Bernhard Schussek <bernhard.schussek@symfony-project.com>
- *
- * This source file is subject to the MIT license that is bundled
- * with this source code in the file LICENSE.
- */
- class LimeCoverage extends LimeRegistration
- {
- const
- COVERED = 1,
- UNCOVERED = -1;
- protected
- $options = array(),
- $files = array(),
- $suite = null,
- $coverage = array(),
- $coveredLines = 0,
- $uncoveredLines = 0,
- $coveredCode = array(),
- $uncoveredCode = array(),
- $actualCode = array();
- public function __construct(LimeTestSuite $suite, array $options = array())
- {
- $this->suite = $suite;
- $this->options = array_merge(array(
- 'base_dir' => null,
- 'extension' => '.php',
- 'verbose' => false,
- ), $options);
- // temporary solution, LimeRegistration needs to be modified
- $this->setBaseDir($this->options['base_dir']);
- $this->setExtension($this->options['extension']);
- if (!function_exists('xdebug_start_code_coverage'))
- {
- throw new Exception('You must install and enable xdebug before using lime coverage.');
- }
- if (!ini_get('xdebug.extended_info'))
- {
- throw new Exception('You must set xdebug.extended_info to 1 in your php.ini to use lime coverage.');
- }
- }
- public function setFiles($files)
- {
- if (!is_array($files))
- {
- $files = array($files);
- }
- $this->files = $files;
- }
- public function run()
- {
- if (!count($this->suite->files))
- {
- throw new Exception('You must register some test files before running coverage!');
- }
- if (!count($this->files))
- {
- throw new Exception('You must register some files to cover!');
- }
- $this->coverage = array();
- $this->process($this->suite->files);
- $this->parseCoverage($this->coverage);
- $this->render();
- }
- protected function process(array $files)
- {
- $this->output = new LimeOutput();
- foreach ($files as $file)
- {
- $command = new LimeShellCommand($file, array('coverage' => true));
- $command->execute();
- // script failed
- if ($command->getStatus() != LimeShell::SUCCESS)
- {
- $this->output->echoln(sprintf('Warning: %s returned status %d, results may be inaccurate', $file, $command->getStatus()), LimeOutput::ERROR);
- }
- // script succeeded, coverage not readable
- if (false === $coverage = @unserialize($command->getOutput()))
- {
- if ($command->getStatus() == LimeShell::SUCCESS)
- {
- throw new Exception(sprintf('Unable to unserialize coverage for file "%s"', $file));
- }
- }
- else
- {
- foreach ($coverage as $file => $lines)
- {
- if (!isset($this->coverage[$file]))
- {
- $this->coverage[$file] = $lines;
- }
- else
- {
- foreach ($lines as $line => $flag)
- {
- if ($flag == self::COVERED)
- {
- $this->coverage[$file][$line] = 1;
- }
- }
- }
- }
- }
- }
- }
- protected function parseCoverage(array $coverage)
- {
- $this->coveredLines = 0;
- $this->uncoveredLines = 0;
- ksort($coverage);
- foreach ($coverage as $file => $lines)
- {
- $this->coveredCode[$file] = array();
- $this->uncoveredCode[$file] = array();
- foreach ($lines as $line => $flag)
- {
- if ($flag == self::COVERED)
- {
- $this->coveredCode[$file][] = $line;
- $this->coveredLines++;
- }
- else
- {
- $this->uncoveredCode[$file][] = $line;
- $this->uncoveredLines++;
- }
- }
- }
- $lexer = new LimeLexerCodeLines();
- foreach ($this->files as $file)
- {
- if (!array_key_exists($file, $this->coveredCode))
- {
- $this->coveredCode[$file] = array();
- $this->uncoveredCode[$file] = $lexer->parse($file);
- $this->uncoveredLines += count($this->uncoveredCode[$file]);
- }
- }
- }
- protected function render()
- {
- $printer = new LimePrinter(new LimeColorizer());
- foreach ($this->files as $file)
- {
- $totalLines = count($this->coveredCode[$file]) + count($this->uncoveredCode[$file]);
- $percent = count($this->coveredCode[$file]) * 100 / max($totalLines, 1);
- $relativeFile = $this->getRelativeFile($file);
- if ($percent == 100)
- {
- $style = LimePrinter::OK;
- }
- else if ($percent >= 90)
- {
- $style = LimePrinter::INFO;
- }
- else if ($percent <= 20)
- {
- $style = LimePrinter::NOT_OK;
- }
- else
- {
- $style = null;
- }
- $printer->printLine(sprintf("%-76s%3.0f%%", $relativeFile, $percent), $style);
- if ($this->options['verbose'] && $percent > 0 && $percent < 100)
- {
- $printer->printLine(sprintf("missing: %s", $this->formatRange($this->uncoveredCode[$file])), LimePrinter::COMMENT);
- }
- }
- $totalLines = $this->coveredLines + $this->uncoveredLines;
- $percent = $this->coveredLines * 100 / max($totalLines, 1);
- if ($percent <= 20)
- {
- $style = LimePrinter::NOT_OK;
- }
- else
- {
- $style = LimePrinter::HAPPY;
- }
- $printer->printLine(str_pad(sprintf(" Total Coverage: %3.0f%%", $percent), 80), $style);
- }
- protected function formatRange(array $lines)
- {
- sort($lines);
- $formatted = '';
- $first = -1;
- $last = -1;
- foreach ($lines as $line)
- {
- if ($last + 1 != $line)
- {
- if ($first != -1)
- {
- $formatted .= $first == $last ? "$first " : "[$first - $last] ";
- }
- $first = $line;
- $last = $line;
- }
- else
- {
- $last = $line;
- }
- }
- if ($first != -1)
- {
- $formatted .= $first == $last ? "$first " : "[$first - $last] ";
- }
- return $formatted;
- }
- }
|