Completed
Pull Request — master (#204)
by
unknown
02:26
created

Reader::__construct()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3.009

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 14
ccs 9
cts 10
cp 0.9
rs 9.4285
cc 3
eloc 9
nc 3
nop 1
crap 3.009
1
<?php
2
namespace ParaTest\Logging\JUnit;
3
4
use ParaTest\Logging\MetaProvider;
5
6
class Reader extends MetaProvider
7
{
8
    /**
9
     * @var \SimpleXMLElement
10
     */
11
    protected $xml;
12
13
    /**
14
     * @var bool
15
     */
16
    protected $isSingle = false;
17
18
    /**
19
     * @var array
20
     */
21
    protected $suites = array();
22
23
    /**
24
     * @var string
25
     */
26
    protected $logFile;
27
28
    /**
29
     * @var array
30
     */
31
    protected static $defaultSuite = array('name' => '',
32
                                           'file' => '',
33
                                           'tests' => 0,
34
                                           'assertions' => 0,
35
                                           'failures' => 0,
36
                                           'errors' => 0,
37
                                           'time' => 0);
38
39 52
    public function __construct($logFile)
40
    {
41 52
        if (!file_exists($logFile)) {
42 1
            throw new \InvalidArgumentException("Log file $logFile does not exist");
43
        }
44
45 52
        $this->logFile = $logFile;
46 52
        if (filesize($logFile) == 0) {
47
            throw new \InvalidArgumentException("Log file $logFile is empty. This means a PHPUnit process has crashed.");
48
        }
49 52
        $logFileContents = file_get_contents($this->logFile);
50 52
        $this->xml = new \SimpleXMLElement($logFileContents);
51 52
        $this->init();
52 52
    }
53
54
    /**
55
     * Returns whether or not this reader contains only
56
     * a single suite
57
     *
58
     * @return bool
59
     */
60 2
    public function isSingleSuite()
61
    {
62 2
        return $this->isSingle;
63
    }
64
65
    /**
66
     * Return the Reader's collection
67
     * of test suites
68
     *
69
     * @return array
70
     */
71 12
    public function getSuites()
72
    {
73 12
        return $this->suites;
74
    }
75
76
    /**
77
     * Checks whether the xml log has
78
     * test suite results
79
     *
80
     * @return array
81
     */
82 12
    public function hasResults()
83
    {
84 12
        return $this->xml->count() > 0;
85
    }
86
87
    /**
88
     * Return an array that contains
89
     * each suite's instant feedback. Since
90
     * logs do not contain skipped or incomplete
91
     * tests this array will contain any number of the following
92
     * characters: .,F,E
93
     *
94
     * @return array
95
     */
96 51
    public function getFeedback()
97
    {
98 12
        $feedback = array();
99 12
        $suites = $this->isSingle ? $this->suites : $this->suites[0]->suites;
100 12
        foreach ($suites as $suite) {
101 12
            foreach ($suite->cases as $case) {
102 12
                if ($case->failures) {
103 8
                    $feedback[] = 'F';
104 12
                } elseif ($case->errors) {
105 9
                    $feedback[] = 'E';
106 9
                } else {
107 12
                    $feedback[] = '.';
108
                }
109 12
            }
110 12
        }
111 51
        return $feedback;
112 51
    }
113
114
    /**
115
     * Remove the JUnit xml file
116
     */
117 51
    public function removeLog()
118 51
    {
119 51
        unlink($this->logFile);
120 51
    }
121
122
    /**
123
     * Initialize the suite collection
124
     * from the JUnit xml document
125
     */
126 52
    protected function init()
127
    {
128 52
        $this->initSuite();
129 52
        $cases = $this->getCaseNodes();
130 52
        foreach ($cases as $file => $nodeArray) {
131 51
            $this->initSuiteFromCases($nodeArray);
132 52
        }
133 52
    }
134
135
    /**
136
     * Uses an array of testcase nodes to build a suite
137
     * @param array $nodeArray an array of SimpleXMLElement nodes representing testcase elements
138
     */
139 51
    protected function initSuiteFromCases($nodeArray)
140
    {
141 51
        $testCases = array();
142 51
        $properties = $this->caseNodesToSuiteProperties($nodeArray, $testCases);
143 51
        if (!$this->isSingle) {
144 41
            $this->addSuite($properties, $testCases);
145 41
        } else {
146 48
            $this->suites[0]->cases = $testCases;
147
        }
148 51
    }
149
150
    /**
151
     * Creates and adds a TestSuite based on the given
152
     * suite properties and collection of test cases
153
     *
154
     * @param $properties
155
     * @param $testCases
156
     */
157 41
    protected function addSuite($properties, $testCases)
158
    {
159 41
        $suite = TestSuite::suiteFromArray($properties);
160 41
        $suite->cases = $testCases;
161 41
        $this->suites[0]->suites[] = $suite;
162 41
    }
163
164
    /**
165
     * Fold an array of testcase nodes into a suite array
166
     * @param array $nodeArray an array of testcase nodes
167
     * @param array $testCases an array reference. Individual testcases will be placed here.
168
     * @return mixed
169
     */
170 51
    protected function caseNodesToSuiteProperties($nodeArray, &$testCases = array())
171
    {
172 51
        $cb = array('ParaTest\\Logging\\JUnit\\TestCase', 'caseFromNode');
173
        return array_reduce($nodeArray, function ($result, $c) use (&$testCases, $cb) {
174 51
            $testCases[] = call_user_func_array($cb, array($c));
175 51
            $result['name'] = (string)$c['class'];
176 51
            $result['file'] = (string)$c['file'];
177 51
            $result['tests'] = $result['tests'] + 1;
178 51
            $result['assertions'] += (int)$c['assertions'];
179 51
            $result['failures'] += sizeof($c->xpath('failure'));
180 51
            $result['errors'] += sizeof($c->xpath('error'));
181 51
            $result['time'] += floatval($c['time']);
182 51
            return $result;
183 51
        }, static::$defaultSuite);
184
    }
185
186
    /**
187
     * Return a collection of testcase nodes
188
     * from the xml document
189
     *
190
     * @return array
191
     */
192 52
    protected function getCaseNodes()
193
    {
194 52
        $caseNodes = $this->xml->xpath('//testcase');
195 52
        $cases = array();
196 52
        while (list( , $node) = each($caseNodes)) {
197 51
            $case = $node;
0 ignored issues
show
Unused Code introduced by
$case is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
198 51
            if (!isset($cases[(string)$node['file']])) {
199 51
                $cases[(string)$node['file']] = array();
200 51
            }
201 51
            $cases[(string)$node['file']][] = $node;
202 51
        }
203 52
        return $cases;
204
    }
205
206
    /**
207
     * Determine if this reader is a single suite
208
     * and initialize the suite collection with the first
209
     * suite
210
     */
211 52
    protected function initSuite()
212
    {
213 52
        $suiteNodes = $this->xml->xpath('/testsuites/testsuite/testsuite');
214 52
        $this->isSingle = sizeof($suiteNodes) === 0;
215 52
        $node = current($this->xml->xpath("/testsuites/testsuite"));
216
217 52
        if ($node !== false) {
218 51
            $this->suites[] = TestSuite::suiteFromNode($node);
219 51
        }
220 52
    }
221
}
222