Skip to content

Commit 0f3ca74

Browse files
committed
Merge pull request #117 from rusitschka/master
Coverage support for WrapperRunner, see #115
2 parents 3fe8bd6 + 0e7ed41 commit 0f3ca74

File tree

4 files changed

+294
-247
lines changed

4 files changed

+294
-247
lines changed
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
<?php namespace ParaTest\Runners\PHPUnit;
2+
3+
use ParaTest\Coverage\CoverageMerger;
4+
use ParaTest\Logging\LogInterpreter;
5+
use ParaTest\Logging\JUnit\Writer;
6+
use PHP_CodeCoverage_Report_Clover;
7+
use PHP_CodeCoverage_Report_HTML;
8+
use PHP_CodeCoverage_Report_PHP;
9+
use RuntimeException;
10+
11+
12+
abstract class BaseRunner
13+
{
14+
const PHPUNIT_FATAL_ERROR = 255;
15+
16+
/**
17+
* @var Options
18+
*/
19+
protected $options;
20+
21+
/**
22+
* @var \ParaTest\Logging\LogInterpreter
23+
*/
24+
protected $interpreter;
25+
26+
/**
27+
* @var ResultPrinter
28+
*/
29+
protected $printer;
30+
31+
/**
32+
* A collection of pending ExecutableTest objects that have
33+
* yet to run
34+
*
35+
* @var array
36+
*/
37+
protected $pending = array();
38+
39+
/**
40+
* A collection of ExecutableTest objects that have processes
41+
* currently running
42+
*
43+
* @var array
44+
*/
45+
protected $running = array();
46+
47+
/**
48+
* A tallied exit code that returns the highest exit
49+
* code returned out of the entire collection of tests
50+
*
51+
* @var int
52+
*/
53+
protected $exitcode = -1;
54+
55+
/**
56+
* CoverageMerger to hold track of the accumulated coverage
57+
*
58+
* @var CoverageMerger
59+
*/
60+
protected $coverage = null;
61+
62+
63+
public function __construct($opts = array())
64+
{
65+
$this->options = new Options($opts);
66+
$this->interpreter = new LogInterpreter();
67+
$this->printer = new ResultPrinter($this->interpreter);
68+
}
69+
70+
public function run()
71+
{
72+
$this->verifyConfiguration();
73+
$this->initCoverage();
74+
$this->load();
75+
$this->printer->start($this->options);
76+
}
77+
78+
/**
79+
* Ensures a valid configuration was supplied. If not
80+
* causes ParaTest to print the error message and exit immediately
81+
* with an exit code of 1
82+
*/
83+
protected function verifyConfiguration()
84+
{
85+
if (isset($this->options->filtered['configuration']) && !file_exists($this->options->filtered['configuration']->getPath())) {
86+
$this->printer->println(sprintf('Could not read "%s".', $this->options->filtered['configuration']));
87+
exit(1);
88+
}
89+
}
90+
91+
/**
92+
* Builds the collection of pending ExecutableTest objects
93+
* to run. If functional mode is enabled $this->pending will
94+
* contain a collection of TestMethod objects instead of Suite
95+
* objects
96+
*/
97+
protected function load()
98+
{
99+
$loader = new SuiteLoader($this->options);
100+
$loader->load($this->options->path);
101+
$executables = $this->options->functional ? $loader->getTestMethods() : $loader->getSuites();
102+
$this->pending = array_merge($this->pending, $executables);
103+
foreach($this->pending as $pending) {
104+
$this->printer->addTest($pending);
105+
}
106+
}
107+
108+
/**
109+
* Returns the highest exit code encountered
110+
* throughout the course of test execution
111+
*
112+
* @return int
113+
*/
114+
public function getExitCode()
115+
{
116+
return $this->exitcode;
117+
}
118+
119+
/**
120+
* Write output to JUnit format if requested
121+
*/
122+
protected function log()
123+
{
124+
if (!isset($this->options->filtered['log-junit'])) {
125+
return;
126+
}
127+
$output = $this->options->filtered['log-junit'];
128+
$writer = new Writer($this->interpreter, $this->options->path);
129+
$writer->write($output);
130+
}
131+
132+
/**
133+
* Write coverage to file if requested
134+
*/
135+
protected function logCoverage()
136+
{
137+
if (!$this->hasCoverage()) {
138+
return;
139+
}
140+
141+
$filteredOptions = $this->options->filtered;
142+
if (isset($filteredOptions['coverage-clover'])) {
143+
$clover = new PHP_CodeCoverage_Report_Clover();
144+
$clover->process($this->getCoverage()->getCoverage(), $filteredOptions['coverage-clover']);
145+
}
146+
147+
if (isset($filteredOptions['coverage-html'])) {
148+
$html = new PHP_CodeCoverage_Report_HTML();
149+
$html->process($this->getCoverage()->getCoverage(), $filteredOptions['coverage-html']);
150+
}
151+
152+
$php = new PHP_CodeCoverage_Report_PHP();
153+
$php->process($this->getCoverage()->getCoverage(), $filteredOptions['coverage-php']);
154+
}
155+
156+
protected function initCoverage()
157+
{
158+
if (!isset($this->options->filtered['coverage-php'])) {
159+
return;
160+
}
161+
162+
$this->coverage = new CoverageMerger();
163+
}
164+
165+
protected function hasCoverage()
166+
{
167+
return $this->getCoverage() != null;
168+
}
169+
170+
/**
171+
* @return CoverageMerger
172+
*/
173+
public function getCoverage()
174+
{
175+
return $this->coverage;
176+
}
177+
178+
/**
179+
* Returns coverage object from file.
180+
*
181+
* @param string $coverageFile Coverage file.
182+
*
183+
* @return \PHP_CodeCoverage
184+
*/
185+
protected function getCoverageObject($coverageFile)
186+
{
187+
$coverage = file_get_contents($coverageFile);
188+
189+
if (substr($coverage, 0, 5) === '<?php') {
190+
return include $coverageFile;
191+
}
192+
193+
// the PHPUnit 3.x and below
194+
return unserialize($coverage);
195+
}
196+
197+
/**
198+
* Adds the coverage contained in $coverageFile and deletes the file afterwards
199+
* @param $coverageFile
200+
* @throws RuntimeException
201+
*/
202+
protected function addCoverageFromFile($coverageFile)
203+
{
204+
if ($coverageFile === null || !file_exists($coverageFile)) {
205+
return;
206+
}
207+
208+
if (filesize($coverageFile) == 0) {
209+
throw new RuntimeException("Coverage file $coverageFile is empty. This means a PHPUnit process has crashed.");
210+
}
211+
212+
$this->getCoverage()->addCoverage($this->getCoverageObject($coverageFile));
213+
unlink($coverageFile);
214+
}
215+
216+
}

0 commit comments

Comments
 (0)