Completed
Pull Request — master (#223)
by Michael
03:44 queued 01:35
created

Writer   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 210
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 21
lcom 1
cbo 2
dl 0
loc 210
ccs 74
cts 74
cp 1
rs 10
c 1
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A getName() 0 4 1
A write() 0 4 1
A getXml() 0 12 3
A appendSuite() 0 12 3
A appendCase() 0 17 4
A appendDefects() 0 8 2
A getSuiteRoot() 0 15 3
A isEmptyLineAttribute() 0 4 2
A getSuiteRootAttributes() 0 11 1
1
<?php
2
namespace ParaTest\Logging\JUnit;
3
4
use ParaTest\Logging\LogInterpreter;
5
6
class Writer
7
{
8
    /**
9
     * The name attribute of the testsuite being
10
     * written
11
     *
12
     * @var string
13
     */
14
    protected $name;
15
16
    /**
17
     * @var \ParaTest\Logging\LogInterpreter
18
     */
19
    protected $interpreter;
20
21
    /**
22
     * @var \DOMDocument
23
     */
24
    protected $document;
25
26
    /**
27
     * A pattern for matching testsuite attributes
28
     *
29
     * @var string
30
     */
31
    protected static $suiteAttrs = '/name|(?:test|assertion|failure|error)s|time|file/';
32
33
    /**
34
     * A pattern for matching testcase attrs
35
     *
36
     * @var string
37
     */
38
    protected static $caseAttrs = '/name|class|file|line|assertions|time/';
39
40
    /**
41
     * A default suite to ease flattening of
42
     * suite structures
43
     *
44
     * @var array
45
     */
46
    protected static $defaultSuite = array(
47
                                        'tests' => 0,
48
                                        'assertions' => 0,
49
                                        'failures' => 0,
50
                                        'errors' => 0,
51
                                        'time' => 0
52
                                    );
53
54 6
    public function __construct(LogInterpreter $interpreter, $name = '')
55
    {
56 6
        $this->name = $name;
57 6
        $this->interpreter = $interpreter;
58 6
        $this->document = new \DOMDocument("1.0", "UTF-8");
59 6
        $this->document->formatOutput = true;
60 6
    }
61
62
    /**
63
     * Get the name of the root suite being written
64
     *
65
     * @return string
66
     */
67 1
    public function getName()
68
    {
69 1
        return $this->name;
70
    }
71
72
    /**
73
     * Returns the xml structure the writer
74
     * will use
75
     *
76
     * @return string
77
     */
78 5
    public function getXml()
79
    {
80 5
        $suites = $this->interpreter->flattenCases();
81 5
        $root = $this->getSuiteRoot($suites);
82 5
        foreach ($suites as $suite) {
83 5
            $snode = $this->appendSuite($root, $suite);
84 5
            foreach ($suite->cases as $case) {
85 5
                $cnode = $this->appendCase($snode, $case);
0 ignored issues
show
Unused Code introduced by
$cnode 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...
86 5
            }
87 5
        }
88 5
        return $this->document->saveXML();
89
    }
90
91
    /**
92
     * Write the xml structure to a file path
93
     *
94
     * @param $path
95
     */
96 2
    public function write($path)
97
    {
98 2
        file_put_contents($path, $this->getXml());
99 2
    }
100
101
    /**
102
     * Append a testsuite node to the given
103
     * root element
104
     *
105
     * @param $root
106
     * @param TestSuite $suite
107
     * @return \DOMElement
108
     */
109 5
    protected function appendSuite($root, TestSuite $suite)
110
    {
111 5
        $suiteNode = $this->document->createElement("testsuite");
112 5
        $vars = get_object_vars($suite);
113 5
        foreach ($vars as $name => $value) {
114 5
            if (preg_match(static::$suiteAttrs, $name)) {
115 5
                $suiteNode->setAttribute($name, $value);
116 5
            }
117 5
        }
118 5
        $root->appendChild($suiteNode);
119 5
        return $suiteNode;
120
    }
121
122
    /**
123
     * Append a testcase node to the given testsuite
124
     * node
125
     *
126
     * @param $suiteNode
127
     * @param TestCase $case
128
     * @return \DOMElement
129
     */
130 5
    protected function appendCase($suiteNode, TestCase $case)
131
    {
132 5
        $caseNode = $this->document->createElement("testcase");
133 5
        $vars = get_object_vars($case);
134 5
        foreach ($vars as $name => $value) {
135 5
            if (preg_match(static::$caseAttrs, $name)) {
136 5
                if ($this->isEmptyLineAttribute($name, $value)) {
137 1
                    continue;
138
                }
139 5
                $caseNode->setAttribute($name, $value);
140 5
            }
141 5
        }
142 5
        $suiteNode->appendChild($caseNode);
143 5
        $this->appendDefects($caseNode, $case->failures, 'failure');
144 5
        $this->appendDefects($caseNode, $case->errors, 'error');
145 5
        return $caseNode;
146
    }
147
148
    /**
149
     * Append error or failure nodes to the given testcase node
150
     *
151
     * @param $caseNode
152
     * @param $defects
153
     * @param $type
154
     */
155 5
    protected function appendDefects($caseNode, $defects, $type)
156
    {
157 5
        foreach ($defects as $defect) {
158 3
            $defectNode = $this->document->createElement($type, htmlentities($defect['text']) . "\n");
159 3
            $defectNode->setAttribute('type', $defect['type']);
160 3
            $caseNode->appendChild($defectNode);
161 5
        }
162 5
    }
163
164
    /**
165
     * Get the root level testsuite node
166
     *
167
     * @param $suites
168
     * @return \DOMElement
169
     */
170 5
    protected function getSuiteRoot($suites)
171
    {
172 5
        $testsuites = $this->document->createElement("testsuites");
173 5
        $this->document->appendChild($testsuites);
174 5
        if (sizeof($suites) == 1) {
175 2
            return $testsuites;
176
        }
177 3
        $rootSuite = $this->document->createElement('testsuite');
178 3
        $attrs = $this->getSuiteRootAttributes($suites);
179 3
        foreach ($attrs as $attr => $value) {
180 3
            $rootSuite->setAttribute($attr, $value);
181 3
        }
182 3
        $testsuites->appendChild($rootSuite);
183 3
        return $rootSuite;
184
    }
185
186
    /**
187
     * Get the attributes used on the root testsuite
188
     * node
189
     *
190
     * @param $suites
191
     * @return mixed
192
     */
193
    protected function getSuiteRootAttributes($suites)
194
    {
195 3
        return array_reduce($suites, function ($result, $suite) {
196 3
            $result['tests'] += $suite->tests;
197 3
            $result['assertions'] += $suite->assertions;
198 3
            $result['failures'] += $suite->failures;
199 3
            $result['errors'] += $suite->errors;
200 3
            $result['time'] += $suite->time;
201 3
            return $result;
202 3
        }, array_merge(array('name' => $this->name), self::$defaultSuite));
203
    }
204
205
    /**
206
     * Prevent writing empty "line" XML attributes which could break parsers.
207
     * @param string $name
208
     * @param mixed $value
209
     * @return bool
210
     */
211 5
    private function isEmptyLineAttribute($name, $value)
212
    {
213 5
        return $name === 'line' && empty($value);
214
    }
215
}
216