1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of Collision. |
5
|
|
|
* |
6
|
|
|
* (c) Nuno Maduro <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace NunoMaduro\Collision\Adapters\Phpunit; |
13
|
|
|
|
14
|
|
|
use NunoMaduro\Collision\Exceptions\ShouldNotHappen; |
15
|
|
|
use PHPUnit\Framework\AssertionFailedError; |
16
|
|
|
use PHPUnit\Framework\Test; |
17
|
|
|
use PHPUnit\Framework\TestCase; |
18
|
|
|
use PHPUnit\Framework\TestListener; |
19
|
|
|
use PHPUnit\Framework\TestSuite; |
20
|
|
|
use PHPUnit\Framework\Warning; |
21
|
|
|
use PHPUnit\Util\Printer; |
22
|
|
|
use ReflectionObject; |
23
|
|
|
use Symfony\Component\Console\Input\ArgvInput; |
24
|
|
|
use Symfony\Component\Console\Input\InputInterface; |
25
|
|
|
use Symfony\Component\Console\Output\ConsoleOutput; |
26
|
|
|
use Throwable; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* This `if` condition exists because phpunit |
30
|
|
|
* is not a direct dependency of Collision. |
31
|
|
|
*/ |
32
|
|
|
if (class_exists(\PHPUnit\Runner\Version::class) && intval(substr(\PHPUnit\Runner\Version::id(), 0, 1)) >= 8) { |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* This is an Collision Phpunit Adapter implementation. |
36
|
|
|
* |
37
|
|
|
* @internal |
38
|
|
|
*/ |
39
|
|
|
final class Listener extends Printer implements TestListener |
|
|
|
|
40
|
|
|
{ |
41
|
|
|
/** |
42
|
|
|
* Holds an instance of the console input. |
43
|
|
|
* |
44
|
|
|
* @var InputInterface |
45
|
|
|
*/ |
46
|
|
|
private $input; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* Holds an instance of the console input. |
50
|
|
|
* |
51
|
|
|
* @var ConsoleOutput |
52
|
|
|
*/ |
53
|
|
|
private $output; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Holds an instance of Section. |
57
|
|
|
* |
58
|
|
|
* @var Section |
59
|
|
|
*/ |
60
|
|
|
private $section; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* The timer. |
64
|
|
|
* |
65
|
|
|
* @var Timer |
66
|
|
|
*/ |
67
|
|
|
private $timer; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* The number of total tests. |
71
|
|
|
* |
72
|
|
|
* @var int|null |
73
|
|
|
*/ |
74
|
|
|
private $totalTests; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Indicates that the method `end` |
78
|
|
|
* was called already. |
79
|
|
|
* |
80
|
|
|
* @var bool |
81
|
|
|
*/ |
82
|
|
|
private $sectionEnded = false; |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* The current test number. |
86
|
|
|
* |
87
|
|
|
* @var int |
88
|
|
|
*/ |
89
|
|
|
private $currentTestNumber = 0; |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* The number of passed tests. |
93
|
|
|
* |
94
|
|
|
* @var int |
95
|
|
|
*/ |
96
|
|
|
private $passedTests = 0; |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* The number of skipped tests. |
100
|
|
|
* |
101
|
|
|
* @var int |
102
|
|
|
*/ |
103
|
|
|
private $skippedTests = 0; |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* The number of warning tests. |
107
|
|
|
* |
108
|
|
|
* @var int |
109
|
|
|
*/ |
110
|
|
|
private $warningsTests = 0; |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* The number of incomplete tests. |
114
|
|
|
* |
115
|
|
|
* @var int |
116
|
|
|
*/ |
117
|
|
|
private $incompleteTests = 0; |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* The number of risky tests. |
121
|
|
|
* |
122
|
|
|
* @var int |
123
|
|
|
*/ |
124
|
|
|
private $riskyTests = 0; |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Creates a new instance of the listener. |
128
|
|
|
* |
129
|
|
|
* @param InputInterface $input |
130
|
|
|
* @param ConsoleOutput $output |
131
|
|
|
* |
132
|
|
|
* @throws \ReflectionException |
133
|
|
|
*/ |
134
|
3 |
|
public function __construct(InputInterface $input = null, ConsoleOutput $output = null) |
135
|
|
|
{ |
136
|
3 |
|
parent::__construct(); |
137
|
|
|
|
138
|
3 |
|
$this->input = $input ?? new ArgvInput(); |
139
|
3 |
|
$this->output = $output ?? new ConsoleOutput(); |
140
|
3 |
|
ConfigureIO::of($this->input, $this->output); |
141
|
3 |
|
$this->section = new Section($this->output); |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Starts the timer. |
145
|
|
|
*/ |
146
|
3 |
|
$this->timer = Timer::start(); |
147
|
3 |
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* {@inheritdoc} |
151
|
|
|
*/ |
152
|
|
|
public function addError(Test $test, \Throwable $throwable, float $time): void |
153
|
|
|
{ |
154
|
|
|
$this->section->fail(); |
155
|
|
|
|
156
|
|
|
OnError::display($this->output, $throwable); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* {@inheritdoc} |
161
|
|
|
*/ |
162
|
|
|
public function addWarning(Test $test, Warning $warning, float $time): void |
163
|
|
|
{ |
164
|
|
|
$this->warningsTests++; |
165
|
|
|
|
166
|
|
|
$this->section->warn($warning); |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* {@inheritdoc} |
171
|
|
|
*/ |
172
|
|
|
public function addFailure(Test $test, AssertionFailedError $error, float $time): void |
173
|
|
|
{ |
174
|
|
|
$this->section->fail(); |
175
|
|
|
|
176
|
|
|
$reflector = new ReflectionObject($error); |
177
|
|
|
|
178
|
|
|
if ($reflector->hasProperty('message')) { |
179
|
|
|
$message = trim((string) preg_replace("/\r|\n/", ' ', $error->getMessage())); |
180
|
|
|
$property = $reflector->getProperty('message'); |
181
|
|
|
$property->setAccessible(true); |
182
|
|
|
$property->setValue($error, $message); |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
OnError::display($this->output, $error); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* {@inheritdoc} |
190
|
|
|
*/ |
191
|
|
|
public function addIncompleteTest(Test $test, \Throwable $t, float $time): void |
192
|
|
|
{ |
193
|
|
|
$this->incompleteTests++; |
194
|
|
|
$this->section->incomplete($t); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* {@inheritdoc} |
199
|
|
|
*/ |
200
|
|
|
public function addRiskyTest(Test $test, \Throwable $t, float $time): void |
201
|
|
|
{ |
202
|
|
|
$this->riskyTests++; |
203
|
|
|
$this->section->risky(); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* {@inheritdoc} |
208
|
|
|
*/ |
209
|
|
|
public function addSkippedTest(Test $test, Throwable $t, float $time): void |
210
|
|
|
{ |
211
|
|
|
$this->skippedTests++; |
212
|
|
|
$this->section->skipped($t); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* {@inheritdoc} |
217
|
|
|
*/ |
218
|
|
|
public function startTestSuite(TestSuite $suite): void |
219
|
|
|
{ |
220
|
|
|
if ($this->totalTests === null) { |
221
|
|
|
$this->totalTests = $suite->count(); |
222
|
|
|
} |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* {@inheritdoc} |
227
|
|
|
*/ |
228
|
|
|
public function endTestSuite(TestSuite $suite): void |
229
|
|
|
{ |
230
|
|
|
if (! $this->sectionEnded && $this->totalTests === $this->currentTestNumber) { |
231
|
|
|
$this->sectionEnded = true; |
232
|
|
|
$this->section->end(); |
233
|
|
|
$this->output->writeln(''); |
234
|
|
|
|
235
|
|
|
$tests = []; |
236
|
|
|
|
237
|
|
|
foreach (['warnings', 'risky', 'incomplete', 'skipped'] as $countName) { |
238
|
|
|
if ($countTests = $this->{$countName . 'Tests'}) { |
239
|
|
|
$tests[] = "<fg=yellow;options=bold>$countTests $countName</>"; |
240
|
|
|
} |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
if ($passedTests = $this->passedTests) { |
244
|
|
|
$tests[] = "<fg=green;options=bold>$passedTests passed</>"; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
$totalTests = $this->totalTests; |
248
|
|
|
$tests[] = "$totalTests total"; |
249
|
|
|
|
250
|
|
|
$this->output->writeln( |
251
|
|
|
sprintf( |
252
|
|
|
' <fg=white;options=bold>Tests: </><fg=default>%s</>', |
253
|
|
|
implode(', ', $tests) |
254
|
|
|
) |
255
|
|
|
); |
256
|
|
|
|
257
|
|
|
$timeElapsed = number_format($this->timer->result(), 2, '.', ''); |
258
|
|
|
$this->output->writeln( |
259
|
|
|
sprintf( |
260
|
|
|
' <fg=white;options=bold>Time: </><fg=default>%ss</>', |
261
|
|
|
$timeElapsed |
262
|
|
|
) |
263
|
|
|
); |
264
|
|
|
} |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* {@inheritdoc} |
269
|
|
|
*/ |
270
|
1 |
|
public function startTest(Test $test): void |
271
|
|
|
{ |
272
|
1 |
|
if (! $test instanceof TestCase) { |
273
|
1 |
|
throw new ShouldNotHappen(); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
$this->currentTestNumber++; |
277
|
|
|
|
278
|
|
|
$this->section->runs($test); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* {@inheritdoc} |
283
|
|
|
*/ |
284
|
|
|
public function endTest(Test $test, float $time): void |
285
|
|
|
{ |
286
|
|
|
if ($this->section->shouldPass) { |
287
|
|
|
$this->passedTests++; |
288
|
|
|
$this->section->pass(); |
289
|
|
|
} |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
/** |
293
|
|
|
* Intencionally left blank as we |
294
|
|
|
* output things on events of the |
295
|
|
|
* listener. |
296
|
|
|
* |
297
|
|
|
* @param string $content |
298
|
|
|
* |
299
|
|
|
* @return void |
300
|
|
|
*/ |
301
|
|
|
public function write(string $content): void |
302
|
|
|
{ |
303
|
|
|
// |
304
|
|
|
} |
305
|
|
|
} |
306
|
|
|
} |
307
|
|
|
|
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.