40% of 650OPs |
43% of 108Lines |
29% of 76Branches |
19% of 105Paths |
# | |
---|---|
1 |
<?php |
2 |
|
3 |
namespace mageekguy\atoum\report\fields\runner\coverage; |
4 |
|
5 |
require_once __DIR__ . '/../../../../../constants.php'; |
6 |
|
7 |
use |
8 |
mageekguy\atoum, |
9 |
mageekguy\atoum\locale, |
10 |
mageekguy\atoum\report, |
11 |
mageekguy\atoum\template, |
12 |
mageekguy\atoum\exceptions, |
13 |
mageekguy\atoum\cli\prompt, |
14 |
mageekguy\atoum\cli\colorizer |
15 |
; |
16 |
|
17 |
class treemap extends report\fields\runner\coverage\cli |
18 |
{ |
19 |
const dataFile = 'data.json'; |
20 |
|
21 |
protected $urlPrompt = null; |
22 |
protected $urlColorizer = null; |
23 |
protected $treemapUrl = ''; |
24 |
protected $projectName = ''; |
25 |
protected $htmlReportBaseUrl = null; |
26 |
protected $resourcesDirectory = array(); |
27 |
protected $destinationDirectory = null; |
28 |
protected $reflectionClassFactory = null; |
29 |
|
30 |
public function __construct($projectName, $destinationDirectory)100% |
31 |
{ |
32 |
parent::__construct(); |
33 |
|
34 |
$this |
35 |
->setProjectName($projectName) |
36 |
->setDestinationDirectory($destinationDirectory) |
37 |
->setAdapter() |
38 |
->setUrlPrompt() |
39 |
->setUrlColorizer() |
40 |
->setTreemapUrl('/') |
41 |
->setResourcesDirectory() |
42 |
; |
43 |
} |
44 |
|
45 |
public function __toString()0% |
46 |
{ |
47 |
$string = ''; |
48 |
|
49 |
if (sizeof($this->coverage) > 0) |
50 |
{ |
51 |
try |
52 |
{ |
53 |
$nodes = array( |
54 |
'coverage' => round($this->coverage->getValue() * 100, 2), |
55 |
'project' => $this->projectName, |
56 |
'name' => '', |
57 |
'fullname' => '', |
58 |
'htmlReportBaseUrl' => $this->htmlReportBaseUrl, |
59 |
'date' => time(), |
60 |
'children' => array() |
61 |
); |
62 |
|
63 |
foreach ($this->coverage->getClasses() as $className => $classPath) |
64 |
{ |
65 |
$node = & $nodes; |
66 |
|
67 |
$class = new \reflectionClass($className); |
68 |
|
69 |
$namespaces = explode('\\', $class->getNamespaceName()); |
70 |
|
71 |
foreach ($namespaces as $namespace) |
72 |
{ |
73 |
$childFound = false; |
74 |
|
75 |
foreach ($node['children'] as $key => $child) |
76 |
{ |
77 |
$childFound = ($child['name'] === $namespace); |
78 |
|
79 |
if ($childFound === true) |
80 |
{ |
81 |
break; |
82 |
} |
83 |
} |
84 |
|
85 |
if ($childFound === false) |
86 |
{ |
87 |
$key = sizeof($node['children']); |
88 |
$node['children'][] = array( |
89 |
'name' => $namespace, |
90 |
'fullname' => $node['fullname'] . ($node['fullname'] == '' ? '' : '\\') . $namespace, |
91 |
'children' => array() |
92 |
); |
93 |
} |
94 |
|
95 |
$node = & $node['children'][$key]; |
96 |
} |
97 |
|
98 |
$child = array( |
99 |
'name' => $class->getShortName(), |
100 |
'fullname' => $node['fullname'] . '\\' . $class->getShortName(), |
101 |
'covered' => $this->coverage->getNumberOfCoveredLinesInClass($className), |
102 |
'coverable' => $this->coverage->getNumberOfCoverableLinesInClass($className), |
103 |
'pourcent' => round($this->coverage->getValueForClass($className) * 100, 2), |
104 |
'children' => array() |
105 |
); |
106 |
|
107 |
$node['children'][] = $child; |
108 |
} |
109 |
|
110 |
if (@file_put_contents($this->destinationDirectory . DIRECTORY_SEPARATOR . self::dataFile, json_encode($nodes)) === false) |
111 |
{ |
112 |
throw new exceptions\runtime($this->locale->_('Unable to write in \'' . $this->destinationDirectory . '\'')); |
113 |
} |
114 |
|
115 |
try |
116 |
{ |
117 |
$resourcesDirectoryIterator = new \recursiveIteratorIterator(new atoum\iterators\filters\recursives\dot($this->resourcesDirectory)); |
118 |
} |
119 |
catch (\exception $exception) |
120 |
{ |
121 |
throw new exceptions\runtime($this->locale->_('Directory \'' . $this->resourcesDirectory . '\' does not exist')); |
122 |
} |
123 |
|
124 |
foreach ($resourcesDirectoryIterator as $file) |
125 |
{ |
126 |
if (@copy($file, $this->destinationDirectory . DIRECTORY_SEPARATOR . $resourcesDirectoryIterator->getSubPathname()) === false) |
127 |
{ |
128 |
throw new exceptions\runtime($this->locale->_('Unable to write in \'' . $this->destinationDirectory . '\'')); |
129 |
} |
130 |
} |
131 |
|
132 |
$string .= $this->urlPrompt . $this->urlColorizer->colorize(sprintf($this->locale->_('Treemap of code coverage are available at %s.'), $this->treemapUrl)) . PHP_EOL; |
133 |
} |
134 |
catch (\exception $exception) |
135 |
{ |
136 |
$string .= $this->urlPrompt . $this->urlColorizer->colorize(sprintf($this->locale->_('Unable to generate code coverage at %s: %s.'), $this->treemapUrl, $exception->getMessage())) . PHP_EOL; |
137 |
} |
138 |
} |
139 |
|
140 |
return $string; |
141 |
} |
142 |
|
143 |
public function getHtmlReportBaseUrl()100% |
144 |
{ |
145 |
return $this->htmlReportBaseUrl; |
146 |
} |
147 |
|
148 |
public function setHtmlReportBaseUrl($url)100% |
149 |
{ |
150 |
$this->htmlReportBaseUrl = (string) $url; |
151 |
|
152 |
return $this; |
153 |
} |
154 |
|
155 |
public function setReflectionClassFactory(\closure $factory)100% |
156 |
{ |
157 |
$closure = new \reflectionMethod($factory, '__invoke'); |
158 |
|
159 |
if ($closure->getNumberOfParameters() != 1) |
160 |
{ |
161 |
throw new exceptions\logic\invalidArgument('Reflection class factory must take one argument'); |
162 |
} |
163 |
|
164 |
$this->reflectionClassFactory = $factory; |
165 |
|
166 |
return $this; |
167 |
} |
168 |
|
169 |
public function getReflectionClass($class)67% |
170 |
{ |
171 |
if ($this->reflectionClassFactory === null) |
172 |
{ |
173 |
$reflectionClass = new \reflectionClass($class); |
174 |
} |
175 |
else |
176 |
{ |
177 |
$reflectionClass = $this->reflectionClassFactory->__invoke($class); |
178 |
|
179 |
if ($reflectionClass instanceof \reflectionClass === false) |
180 |
{ |
181 |
throw new exceptions\runtime\unexpectedValue('Reflection class injector must return a \reflectionClass instance'); |
182 |
} |
183 |
} |
184 |
|
185 |
return $reflectionClass; |
186 |
} |
187 |
|
188 |
public function setProjectName($projectName)100% |
189 |
{ |
190 |
$this->projectName = (string) $projectName; |
191 |
|
192 |
return $this; |
193 |
} |
194 |
|
195 |
public function getProjectName()100% |
196 |
{ |
197 |
return $this->projectName; |
198 |
} |
199 |
|
200 |
public function setDestinationDirectory($path)100% |
201 |
{ |
202 |
$this->destinationDirectory = (string) $path; |
203 |
|
204 |
return $this; |
205 |
} |
206 |
|
207 |
public function getDestinationDirectory()100% |
208 |
{ |
209 |
return $this->destinationDirectory; |
210 |
} |
211 |
|
212 |
public function setAdapter(atoum\adapter $adapter = null)100% |
213 |
{ |
214 |
$this->adapter = $adapter ?: new atoum\adapter(); |
215 |
|
216 |
return $this; |
217 |
} |
218 |
|
219 |
public function getAdapter()100% |
220 |
{ |
221 |
return $this->adapter; |
222 |
} |
223 |
|
224 |
public function setUrlPrompt(prompt $prompt = null)100% |
225 |
{ |
226 |
$this->urlPrompt = $prompt ?: new prompt(); |
227 |
|
228 |
return $this; |
229 |
} |
230 |
|
231 |
public function getUrlPrompt()100% |
232 |
{ |
233 |
return $this->urlPrompt; |
234 |
} |
235 |
|
236 |
public function setUrlColorizer(colorizer $colorizer = null)100% |
237 |
{ |
238 |
$this->urlColorizer = $colorizer ?: new colorizer(); |
239 |
|
240 |
return $this; |
241 |
} |
242 |
|
243 |
public function getUrlColorizer()100% |
244 |
{ |
245 |
return $this->urlColorizer; |
246 |
} |
247 |
|
248 |
public function setTreemapUrl($treemapUrl)100% |
249 |
{ |
250 |
$this->treemapUrl = (string) $treemapUrl; |
251 |
|
252 |
return $this; |
253 |
} |
254 |
|
255 |
public function getTreemapUrl()100% |
256 |
{ |
257 |
return $this->treemapUrl; |
258 |
} |
259 |
|
260 |
public function setResourcesDirectory($directory = null)100% |
261 |
{ |
262 |
$this->resourcesDirectory = $directory ?: atoum\directory . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'coverage' . DIRECTORY_SEPARATOR . 'treemap'; |
263 |
|
264 |
return $this; |
265 |
} |
266 |
|
267 |
public function getResourcesDirectory()100% |
268 |
{ |
269 |
return $this->resourcesDirectory; |
270 |
} |
271 |
} |