1<?php
2/*
3 * This file is part of the php-code-coverage package.
4 *
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11namespace SebastianBergmann\CodeCoverage\Node;
12
13use SebastianBergmann\CodeCoverage\InvalidArgumentException;
14
15/**
16 * Represents a directory in the code coverage information tree.
17 */
18class Directory extends AbstractNode implements \IteratorAggregate
19{
20    /**
21     * @var AbstractNode[]
22     */
23    private $children = [];
24
25    /**
26     * @var Directory[]
27     */
28    private $directories = [];
29
30    /**
31     * @var File[]
32     */
33    private $files = [];
34
35    /**
36     * @var array
37     */
38    private $classes;
39
40    /**
41     * @var array
42     */
43    private $traits;
44
45    /**
46     * @var array
47     */
48    private $functions;
49
50    /**
51     * @var array
52     */
53    private $linesOfCode = null;
54
55    /**
56     * @var int
57     */
58    private $numFiles = -1;
59
60    /**
61     * @var int
62     */
63    private $numExecutableLines = -1;
64
65    /**
66     * @var int
67     */
68    private $numExecutedLines = -1;
69
70    /**
71     * @var int
72     */
73    private $numClasses = -1;
74
75    /**
76     * @var int
77     */
78    private $numTestedClasses = -1;
79
80    /**
81     * @var int
82     */
83    private $numTraits = -1;
84
85    /**
86     * @var int
87     */
88    private $numTestedTraits = -1;
89
90    /**
91     * @var int
92     */
93    private $numMethods = -1;
94
95    /**
96     * @var int
97     */
98    private $numTestedMethods = -1;
99
100    /**
101     * @var int
102     */
103    private $numFunctions = -1;
104
105    /**
106     * @var int
107     */
108    private $numTestedFunctions = -1;
109
110    /**
111     * Returns the number of files in/under this node.
112     *
113     * @return int
114     */
115    public function count()
116    {
117        if ($this->numFiles == -1) {
118            $this->numFiles = 0;
119
120            foreach ($this->children as $child) {
121                $this->numFiles += count($child);
122            }
123        }
124
125        return $this->numFiles;
126    }
127
128    /**
129     * Returns an iterator for this node.
130     *
131     * @return \RecursiveIteratorIterator
132     */
133    public function getIterator()
134    {
135        return new \RecursiveIteratorIterator(
136            new Iterator($this),
137            \RecursiveIteratorIterator::SELF_FIRST
138        );
139    }
140
141    /**
142     * Adds a new directory.
143     *
144     * @param string $name
145     *
146     * @return Directory
147     */
148    public function addDirectory($name)
149    {
150        $directory = new self($name, $this);
151
152        $this->children[]    = $directory;
153        $this->directories[] = &$this->children[count($this->children) - 1];
154
155        return $directory;
156    }
157
158    /**
159     * Adds a new file.
160     *
161     * @param string $name
162     * @param array  $coverageData
163     * @param array  $testData
164     * @param bool   $cacheTokens
165     *
166     * @return File
167     *
168     * @throws InvalidArgumentException
169     */
170    public function addFile($name, array $coverageData, array $testData, $cacheTokens)
171    {
172        $file = new File(
173            $name,
174            $this,
175            $coverageData,
176            $testData,
177            $cacheTokens
178        );
179
180        $this->children[] = $file;
181        $this->files[]    = &$this->children[count($this->children) - 1];
182
183        $this->numExecutableLines = -1;
184        $this->numExecutedLines   = -1;
185
186        return $file;
187    }
188
189    /**
190     * Returns the directories in this directory.
191     *
192     * @return array
193     */
194    public function getDirectories()
195    {
196        return $this->directories;
197    }
198
199    /**
200     * Returns the files in this directory.
201     *
202     * @return array
203     */
204    public function getFiles()
205    {
206        return $this->files;
207    }
208
209    /**
210     * Returns the child nodes of this node.
211     *
212     * @return array
213     */
214    public function getChildNodes()
215    {
216        return $this->children;
217    }
218
219    /**
220     * Returns the classes of this node.
221     *
222     * @return array
223     */
224    public function getClasses()
225    {
226        if ($this->classes === null) {
227            $this->classes = [];
228
229            foreach ($this->children as $child) {
230                $this->classes = array_merge(
231                    $this->classes,
232                    $child->getClasses()
233                );
234            }
235        }
236
237        return $this->classes;
238    }
239
240    /**
241     * Returns the traits of this node.
242     *
243     * @return array
244     */
245    public function getTraits()
246    {
247        if ($this->traits === null) {
248            $this->traits = [];
249
250            foreach ($this->children as $child) {
251                $this->traits = array_merge(
252                    $this->traits,
253                    $child->getTraits()
254                );
255            }
256        }
257
258        return $this->traits;
259    }
260
261    /**
262     * Returns the functions of this node.
263     *
264     * @return array
265     */
266    public function getFunctions()
267    {
268        if ($this->functions === null) {
269            $this->functions = [];
270
271            foreach ($this->children as $child) {
272                $this->functions = array_merge(
273                    $this->functions,
274                    $child->getFunctions()
275                );
276            }
277        }
278
279        return $this->functions;
280    }
281
282    /**
283     * Returns the LOC/CLOC/NCLOC of this node.
284     *
285     * @return array
286     */
287    public function getLinesOfCode()
288    {
289        if ($this->linesOfCode === null) {
290            $this->linesOfCode = ['loc' => 0, 'cloc' => 0, 'ncloc' => 0];
291
292            foreach ($this->children as $child) {
293                $linesOfCode = $child->getLinesOfCode();
294
295                $this->linesOfCode['loc']   += $linesOfCode['loc'];
296                $this->linesOfCode['cloc']  += $linesOfCode['cloc'];
297                $this->linesOfCode['ncloc'] += $linesOfCode['ncloc'];
298            }
299        }
300
301        return $this->linesOfCode;
302    }
303
304    /**
305     * Returns the number of executable lines.
306     *
307     * @return int
308     */
309    public function getNumExecutableLines()
310    {
311        if ($this->numExecutableLines == -1) {
312            $this->numExecutableLines = 0;
313
314            foreach ($this->children as $child) {
315                $this->numExecutableLines += $child->getNumExecutableLines();
316            }
317        }
318
319        return $this->numExecutableLines;
320    }
321
322    /**
323     * Returns the number of executed lines.
324     *
325     * @return int
326     */
327    public function getNumExecutedLines()
328    {
329        if ($this->numExecutedLines == -1) {
330            $this->numExecutedLines = 0;
331
332            foreach ($this->children as $child) {
333                $this->numExecutedLines += $child->getNumExecutedLines();
334            }
335        }
336
337        return $this->numExecutedLines;
338    }
339
340    /**
341     * Returns the number of classes.
342     *
343     * @return int
344     */
345    public function getNumClasses()
346    {
347        if ($this->numClasses == -1) {
348            $this->numClasses = 0;
349
350            foreach ($this->children as $child) {
351                $this->numClasses += $child->getNumClasses();
352            }
353        }
354
355        return $this->numClasses;
356    }
357
358    /**
359     * Returns the number of tested classes.
360     *
361     * @return int
362     */
363    public function getNumTestedClasses()
364    {
365        if ($this->numTestedClasses == -1) {
366            $this->numTestedClasses = 0;
367
368            foreach ($this->children as $child) {
369                $this->numTestedClasses += $child->getNumTestedClasses();
370            }
371        }
372
373        return $this->numTestedClasses;
374    }
375
376    /**
377     * Returns the number of traits.
378     *
379     * @return int
380     */
381    public function getNumTraits()
382    {
383        if ($this->numTraits == -1) {
384            $this->numTraits = 0;
385
386            foreach ($this->children as $child) {
387                $this->numTraits += $child->getNumTraits();
388            }
389        }
390
391        return $this->numTraits;
392    }
393
394    /**
395     * Returns the number of tested traits.
396     *
397     * @return int
398     */
399    public function getNumTestedTraits()
400    {
401        if ($this->numTestedTraits == -1) {
402            $this->numTestedTraits = 0;
403
404            foreach ($this->children as $child) {
405                $this->numTestedTraits += $child->getNumTestedTraits();
406            }
407        }
408
409        return $this->numTestedTraits;
410    }
411
412    /**
413     * Returns the number of methods.
414     *
415     * @return int
416     */
417    public function getNumMethods()
418    {
419        if ($this->numMethods == -1) {
420            $this->numMethods = 0;
421
422            foreach ($this->children as $child) {
423                $this->numMethods += $child->getNumMethods();
424            }
425        }
426
427        return $this->numMethods;
428    }
429
430    /**
431     * Returns the number of tested methods.
432     *
433     * @return int
434     */
435    public function getNumTestedMethods()
436    {
437        if ($this->numTestedMethods == -1) {
438            $this->numTestedMethods = 0;
439
440            foreach ($this->children as $child) {
441                $this->numTestedMethods += $child->getNumTestedMethods();
442            }
443        }
444
445        return $this->numTestedMethods;
446    }
447
448    /**
449     * Returns the number of functions.
450     *
451     * @return int
452     */
453    public function getNumFunctions()
454    {
455        if ($this->numFunctions == -1) {
456            $this->numFunctions = 0;
457
458            foreach ($this->children as $child) {
459                $this->numFunctions += $child->getNumFunctions();
460            }
461        }
462
463        return $this->numFunctions;
464    }
465
466    /**
467     * Returns the number of tested functions.
468     *
469     * @return int
470     */
471    public function getNumTestedFunctions()
472    {
473        if ($this->numTestedFunctions == -1) {
474            $this->numTestedFunctions = 0;
475
476            foreach ($this->children as $child) {
477                $this->numTestedFunctions += $child->getNumTestedFunctions();
478            }
479        }
480
481        return $this->numTestedFunctions;
482    }
483}
484