1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Humbug |
4
|
|
|
* |
5
|
|
|
* @category Humbug |
6
|
|
|
* @package Humbug |
7
|
|
|
* @copyright Copyright (c) 2015 Pádraic Brady (http://blog.astrumfutura.com) |
8
|
|
|
* @license https://github.com/padraic/humbug/blob/master/LICENSE New BSD License |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace Humbug\Adapter\Phpunit; |
12
|
|
|
|
13
|
|
|
use Humbug\Adapter\Phpunit\XmlConfiguration\Visitor; |
14
|
|
|
use Humbug\Exception\LogicException; |
15
|
|
|
|
16
|
|
|
class XmlConfiguration |
17
|
|
|
{ |
18
|
|
|
/** |
19
|
|
|
* |
20
|
|
|
* @var \DOMDocument |
21
|
|
|
*/ |
22
|
|
|
private $dom; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* @var \DOMXPath |
26
|
|
|
*/ |
27
|
|
|
private $xpath; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var \DOMElement |
31
|
|
|
*/ |
32
|
|
|
private $rootElement; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var string|boolean |
36
|
|
|
*/ |
37
|
|
|
private $originalBootstrap; |
38
|
|
|
|
39
|
|
|
public function __construct(\DOMDocument $dom) |
40
|
|
|
{ |
41
|
|
|
if (!$dom->documentElement) { |
42
|
|
|
throw new LogicException('No document element present. Document should not be empty!'); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
$this->dom = $dom; |
46
|
|
|
$this->xpath = new \DOMXPath($this->dom); |
47
|
|
|
$this->rootElement = $this->dom->documentElement; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
public function hasBootstrap() |
51
|
|
|
{ |
52
|
|
|
return $this->rootElement->hasAttribute('bootstrap'); |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
public function getBootstrap() |
56
|
|
|
{ |
57
|
|
|
return $this->rootElement->getAttribute('bootstrap'); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
public function setBootstrap($bootstrap) |
61
|
|
|
{ |
62
|
|
|
if (null === $this->originalBootstrap) { |
63
|
|
|
$actualBootstrap = $this->getBootstrap(); |
64
|
|
|
$this->originalBootstrap = $actualBootstrap ?: false; |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
return $this->rootElement->setAttribute('bootstrap', $bootstrap); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
public function hasOriginalBootstrap() |
71
|
|
|
{ |
72
|
|
|
return ($this->getOriginalBootstrap() !== null); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
public function getOriginalBootstrap() |
76
|
|
|
{ |
77
|
|
|
if (null !== $this->originalBootstrap) { |
78
|
|
|
return $this->originalBootstrap ?: null; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
return $this->getBootstrap() ?: null; |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Given how PHPUnit nests suites, if there's more than one, the suite containing |
86
|
|
|
* actual tests will be two levels down the hierarchy from where we'd normally |
87
|
|
|
* find it with a single testsuite. |
88
|
|
|
* |
89
|
|
|
* @return integer |
90
|
|
|
*/ |
91
|
|
|
public function getRootTestSuiteNestingLevel() |
92
|
|
|
{ |
93
|
|
|
$list = $this->xpath->query('//testsuite'); |
94
|
|
|
if ($list->length == 1) { |
95
|
|
|
return 0; |
96
|
|
|
} |
97
|
|
|
return 1; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
public function turnOffCacheTokens() |
101
|
|
|
{ |
102
|
|
|
return $this->rootElement->setAttribute('cacheTokens', 'false'); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
public function cleanupLoggers() |
106
|
|
|
{ |
107
|
|
|
$this->removeDocumentChildElementsByName('logging'); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
public function cleanupFilters() |
111
|
|
|
{ |
112
|
|
|
$this->removeDocumentChildElementsByName('filter'); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
public function cleanupListeners() |
116
|
|
|
{ |
117
|
|
|
$this->removeDocumentChildElementsByName('listeners'); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
public function addListener(Visitor $visitor) |
121
|
|
|
{ |
122
|
|
|
$listenersList = $this->xpath->query('/phpunit/listeners'); |
123
|
|
|
|
124
|
|
|
if ($listenersList->length) { |
125
|
|
|
$listeners = $listenersList->item(0); |
126
|
|
|
} else { |
127
|
|
|
$listeners = $this->dom->createElement('listeners'); |
128
|
|
|
$this->rootElement->appendChild($listeners); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
$listener = $this->dom->createElement('listener'); |
132
|
|
|
$listeners->appendChild($listener); |
133
|
|
|
$visitor->visitElement($listener); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
View Code Duplication |
public function addLogger($type, $target) |
|
|
|
|
137
|
|
|
{ |
138
|
|
|
$loggingList = $this->xpath->query('/phpunit/logging'); |
139
|
|
|
|
140
|
|
|
if ($loggingList->length) { |
141
|
|
|
$logging = $loggingList->item(0); |
142
|
|
|
} else { |
143
|
|
|
$logging = $this->dom->createElement('logging'); |
144
|
|
|
$this->rootElement->appendChild($logging); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
$log = $this->dom->createElement('log'); |
148
|
|
|
$logging->appendChild($log); |
149
|
|
|
|
150
|
|
|
$log->setAttribute('type', $type); |
151
|
|
|
$log->setAttribute('target', $target); |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* Adds a <php><env name="XXX" value="YYY"/></php> to set environment variables |
156
|
|
|
* and generates the <php> block if not present. |
157
|
|
|
* |
158
|
|
|
* @param string $name Environment variable name |
159
|
|
|
* @param string $value Value of the variable to set |
160
|
|
|
*/ |
161
|
|
View Code Duplication |
public function addEnvironmentVariable($name, $value) |
|
|
|
|
162
|
|
|
{ |
163
|
|
|
$phpNodeList = $this->xpath->query('/phpunit/php'); |
164
|
|
|
|
165
|
|
|
if ($phpNodeList->length) { |
166
|
|
|
$phpNode = $phpNodeList->item(0); |
167
|
|
|
} else { |
168
|
|
|
$phpNode = $this->dom->createElement('php'); |
169
|
|
|
$this->rootElement->appendChild($phpNode); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
$env = $this->dom->createElement('env'); |
173
|
|
|
$phpNode->appendChild($env); |
174
|
|
|
|
175
|
|
|
$env->setAttribute('name', $name); |
176
|
|
|
$env->setAttribute('value', $value); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
public function addWhiteListFilter(array $whiteListDirectories, array $excludeDirectories = []) |
180
|
|
|
{ |
181
|
|
|
if (empty($whiteListDirectories)) { |
182
|
|
|
return; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
$filter = $this->dom->createElement('filter'); |
186
|
|
|
$this->rootElement->appendChild($filter); |
187
|
|
|
|
188
|
|
|
$whiteList = $this->dom->createElement('whitelist'); |
189
|
|
|
$filter->appendChild($whiteList); |
190
|
|
|
|
191
|
|
|
foreach ($whiteListDirectories as $dirName) { |
192
|
|
|
$directory = $this->dom->createElement('directory', $dirName); |
193
|
|
|
$whiteList->appendChild($directory); |
194
|
|
|
$directory->setAttribute('suffix', '.php'); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
if (empty($excludeDirectories)) { |
198
|
|
|
return; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
$exclude = $this->dom->createElement('exclude'); |
202
|
|
|
$whiteList->appendChild($exclude); |
203
|
|
|
|
204
|
|
|
foreach ($excludeDirectories as $dirName) { |
205
|
|
|
$directory = $this->dom->createElement('directory', $dirName); |
206
|
|
|
$exclude->appendChild($directory); |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
public function replacePathsToAbsolutePaths(Visitor $pathVisitor, Visitor $wildcardVisitor) |
211
|
|
|
{ |
212
|
|
|
$replacePaths = [ |
213
|
|
|
'/phpunit/testsuites/testsuite/exclude', |
214
|
|
|
'//directory', |
215
|
|
|
'//file', |
216
|
|
|
'/phpunit/@bootstrap' |
217
|
|
|
]; |
218
|
|
|
|
219
|
|
|
$replaceQuery = implode('|', $replacePaths); |
220
|
|
|
|
221
|
|
|
$replaceNodes = $this->xpath->query($replaceQuery); |
222
|
|
|
|
223
|
|
|
foreach ($replaceNodes as $replace) { |
224
|
|
|
if (false !== strpos($replace->nodeValue, '*')) { |
225
|
|
|
$wildcardVisitor->visitElement($replace); |
226
|
|
|
} else { |
227
|
|
|
$pathVisitor->visitElement($replace); |
228
|
|
|
} |
229
|
|
|
} |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
public function generateXML() |
233
|
|
|
{ |
234
|
|
|
return $this->dom->saveXML(); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
private function removeDocumentChildElementsByName($name) |
238
|
|
|
{ |
239
|
|
|
$nodes = $this->xpath->query('/phpunit/' . $name); |
240
|
|
|
|
241
|
|
|
foreach ($nodes as $node) { |
242
|
|
|
$this->rootElement->removeChild($node); |
243
|
|
|
} |
244
|
|
|
} |
245
|
|
|
} |
246
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.