Passed
Push — master ( f5ddaa...58b692 )
by Siad
09:28
created

PHPUnitTestRunner9::getLastErrorMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19
20
/**
21
 * Simple Testrunner for PHPUnit that runs all tests of a testsuite.
22
 *
23
 * @author  Blair Cooper <[email protected]>
24
 * @package phing.tasks.ext.phpunit
25
 */
26
class PHPUnitTestRunner9 implements \PHPUnit\Runner\TestHook, \PHPUnit\Framework\TestListener
0 ignored issues
show
Deprecated Code introduced by
The interface PHPUnit\Framework\TestListener has been deprecated: Use the `TestHook` interfaces instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

26
class PHPUnitTestRunner9 implements \PHPUnit\Runner\TestHook, /** @scrutinizer ignore-deprecated */ \PHPUnit\Framework\TestListener

This interface has been deprecated. The supplier of the interface has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the interface will be removed and what other interface to use instead.

Loading history...
27
{
28
    private $hasErrors = false;
29
    private $hasFailures = false;
30
    private $hasWarnings = false;
31
    private $hasIncomplete = false;
32
    private $hasSkipped = false;
33
    private $hasRisky = false;
34
    private $lastErrorMessage = '';
35
    private $lastFailureMessage = '';
36
    private $lastWarningMessage = '';
37
    private $lastIncompleteMessage = '';
38
    private $lastSkippedMessage = '';
39
    private $lastRiskyMessage = '';
40
    private $formatters = [];
41
42
    /**
43
     * @var \PHPUnit\Framework\TestListener[]
44
     */
45
    private $listeners = [];
46
47
    /**
48
     * @var \SebastianBergmann\CodeCoverage\CodeCoverage
49
     */
50
    private $codecoverage;
51
52
    /**
53
     * @var Project $project
54
     */
55
    private $project;
56
57
    private $groups = [];
58
    private $excludeGroups = [];
59
60
    private $processIsolation = false;
61
62
    private $useCustomErrorHandler = true;
63
64
    /**
65
     * @param Project $project
66
     * @param array $groups
67
     * @param array $excludeGroups
68
     * @param bool $processIsolation
69
     */
70 4
    public function __construct(
71
        Project $project,
72
        array $groups = [],
73
        array $excludeGroups = [],
74
        bool $processIsolation = false
75
    ) {
76 4
        $this->project = $project;
77 4
        $this->groups = $groups;
78 4
        $this->excludeGroups = $excludeGroups;
79 4
        $this->processIsolation = $processIsolation;
80 4
    }
81
82
    /**
83
     * @param $codecoverage
84
     */
85
    public function setCodecoverage(\SebastianBergmann\CodeCoverage\CodeCoverage $codecoverage): void
86
    {
87
        $this->codecoverage = $codecoverage;
88
    }
89
90
    /**
91
     * @param $useCustomErrorHandler
92
     */
93 4
    public function setUseCustomErrorHandler(bool $useCustomErrorHandler): void
94
    {
95 4
        $this->useCustomErrorHandler = $useCustomErrorHandler;
96 4
    }
97
98
    /**
99
     * @param $formatter
100
     */
101 2
    public function addFormatter(\PHPUnit\Framework\TestListener $formatter): void
102
    {
103 2
        $this->addListener($formatter);
104 2
        $this->formatters[] = $formatter;
105 2
    }
106
107 2
    public function addListener(\PHPUnit\Framework\TestListener $listener): void
108
    {
109 2
        $this->listeners[] = $listener;
110 2
    }
111
112
    /**
113
     * @param $level
114
     * @param $message
115
     * @param $file
116
     * @param $line
117
     * @return bool
118
     */
119 98
    public function handleError(int $level, string $message, string $file, int $line): bool
120
    {
121 98
        $invoke = new PHPUnit\Util\ErrorHandler(true, true, true, true);
122 98
        return $invoke($level, $message, $file, $line);
123
    }
124
125
    /**
126
     * Run a test
127
     *
128
     * @param  PHPUnit\Framework\TestSuite $suite
129
     * @throws \BuildException
130
     * @throws ReflectionException
131
     */
132 4
    public function run(PHPUnit\Framework\TestSuite $suite)
133
    {
134 4
        $res = new PHPUnit\Framework\TestResult();
135
136 4
        if ($this->codecoverage) {
137
            // Check if Phing coverage is being utlizied
138
            if ($this->project->getProperty('coverage.database')) {
139
                $whitelist = \Phing\Tasks\Ext\Coverage\CoverageMerger::getWhiteList($this->project);
140
                $filter = $this->codecoverage->filter();
141
142
                if (method_exists($filter, 'includeFiles')) {
143
                    $filter->includeFiles($whitelist);
144
                } else if (method_exists($filter, 'addFilesToWhiteList')) {
145
                    $filter->addFilesToWhiteList($whitelist);
146
                }
147
            }
148
149
            $res->setCodeCoverage($this->codecoverage);
150
        }
151
152
        // $res->addListener($this);
153
154 4
        foreach ($this->formatters as $formatter) {
155 2
            $res->addListener($formatter);
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\TestResult::addListener() has been deprecated: Use the `TestHook` interfaces instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

155
            /** @scrutinizer ignore-deprecated */ $res->addListener($formatter);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
156
        }
157
158
        /* Set PHPUnit error handler */
159 4
        if ($this->useCustomErrorHandler) {
160 4
            set_error_handler([$this, 'handleError'], E_ALL | E_STRICT);
161
        }
162
163 4
        $this->injectFilters($suite);
164 4
        $suite->run($res);
165
166 4
        foreach ($this->formatters as $formatter) {
167 2
            $formatter->processResult($res);
168
        }
169
170
        /* Restore Phing error handler */
171 4
        if ($this->useCustomErrorHandler) {
172 4
            restore_error_handler();
173
        }
174
175
        // Check if Phing coverage is being utlizied
176 4
        if ($this->codecoverage && $this->project->getProperty('coverage.database')) {
177
            try {
178
                \Phing\Tasks\Ext\Coverage\CoverageMerger::merge($this->project, $this->codecoverage->getData());
179
            } catch (IOException $e) {
180
                throw new BuildException('Merging code coverage failed.', $e);
181
            }
182
        }
183 4
        $this->checkResult($res);
184 4
    }
185
186
    /**
187
     * @param PHPUnit\Framework\TestSuite $suite
188
     * @throws ReflectionException
189
     */
190 4
    private function injectFilters(PHPUnit\Framework\TestSuite $suite): void
191
    {
192 4
        $filterFactory = new PHPUnit\Runner\Filter\Factory();
193
194 4
        if (empty($this->excludeGroups) && empty($this->groups)) {
195 4
            return;
196
        }
197
198
        if (!empty($this->excludeGroups)) {
199
            $filterFactory->addFilter(
200
                new ReflectionClass(\PHPUnit\Runner\Filter\ExcludeGroupFilterIterator::class),
201
                $this->excludeGroups
202
            );
203
        }
204
205
        if (!empty($this->groups)) {
206
            $filterFactory->addFilter(
207
                new ReflectionClass(\PHPUnit\Runner\Filter\IncludeGroupFilterIterator::class),
208
                $this->groups
209
            );
210
        }
211
212
        $suite->injectFilter($filterFactory);
213
    }
214
215
    /**
216
     * @param \PHPUnit\Framework\TestResult $res
217
     */
218 4
    private function checkResult(\PHPUnit\Framework\TestResult $res): void
219
    {
220 4
        $this->hasSkipped = $res->skippedCount() > 0;
221 4
        $this->hasIncomplete = $res->notImplementedCount() > 0;
222 4
        $this->hasWarnings = $res->warningCount() > 0;
223 4
        $this->hasFailures = $res->failureCount() > 0;
224 4
        $this->hasErrors = $res->errorCount() > 0;
225 4
        $this->hasRisky = $res->riskyCount() > 0;
226 4
    }
227
228
    /**
229
     * @return boolean
230
     */
231 4
    public function hasErrors(): bool
232
    {
233 4
        return $this->hasErrors;
234
    }
235
236
    /**
237
     * @return boolean
238
     */
239 4
    public function hasFailures(): bool
240
    {
241 4
        return $this->hasFailures;
242
    }
243
244
    /**
245
     * @return boolean
246
     */
247 4
    public function hasWarnings(): bool
248
    {
249 4
        return $this->hasWarnings;
250
    }
251
252
    /**
253
     * @return boolean
254
     */
255 4
    public function hasIncomplete(): bool
256
    {
257 4
        return $this->hasIncomplete;
258
    }
259
260
    /**
261
     * @return boolean
262
     */
263 4
    public function hasSkipped(): bool
264
    {
265 4
        return $this->hasSkipped;
266
    }
267
268
    /**
269
     * @return boolean
270
     */
271 4
    public function hasRisky(): bool
272
    {
273 4
        return $this->hasRisky;
274
    }
275
276
    /**
277
     * @return string
278
     */
279
    public function getLastErrorMessage(): string
280
    {
281
        return $this->lastErrorMessage;
282
    }
283
284
    /**
285
     * @return string
286
     */
287 1
    public function getLastFailureMessage(): string
288
    {
289 1
        return $this->lastFailureMessage;
290
    }
291
292
    /**
293
     * @return string
294
     */
295
    public function getLastIncompleteMessage(): string
296
    {
297
        return $this->lastIncompleteMessage;
298
    }
299
300
    /**
301
     * @return string
302
     */
303
    public function getLastSkippedMessage(): string
304
    {
305
        return $this->lastSkippedMessage;
306
    }
307
308
    /**
309
     * @return string
310
     */
311
    public function getLastWarningMessage(): string
312
    {
313
        return $this->lastWarningMessage;
314
    }
315
316
    /**
317
     * @return string
318
     */
319
    public function getLastRiskyMessage(): string
320
    {
321
        return $this->lastRiskyMessage;
322
    }
323
324
    /**
325
     * An error occurred.
326
     *
327
     * @param PHPUnit\Framework\Test $test
328
     * @param Throwable $e
329
     * @param float $time
330
     */
331
    public function addError(PHPUnit\Framework\Test $test, Throwable $e, float $time): void
332
    {
333
        $this->lastErrorMessage = $this->composeMessage('ERROR', $test, $e);
334
    }
335
336
    /**
337
     * @param string $message
338
     * @param PHPUnit\Framework\Test $test
339
     * @param Throwable $e
340
     * @return string
341
     */
342
    protected function composeMessage(string $message, PHPUnit\Framework\Test $test, Throwable $e): string
343
    {
344
        $name = ($test instanceof \PHPUnit\Framework\TestCase ? $test->getName() : '');
345
        $message = "Test {$message} ({$name} in class " . get_class($test) . ' ' . $e->getFile()
346
            . ' on line ' . $e->getLine() . '): ' . $e->getMessage();
347
348
        if ($e instanceof PHPUnit\Framework\ExpectationFailedException && $e->getComparisonFailure()) {
349
            $message .= "\n" . $e->getComparisonFailure()->getDiff();
350
        }
351
352
        return $message;
353
    }
354
355
    /**
356
     * A failure occurred.
357
     *
358
     * @param PHPUnit\Framework\Test $test
359
     * @param PHPUnit\Framework\AssertionFailedError $e
360
     * @param float $time
361
     */
362
    public function addFailure(
363
        PHPUnit\Framework\Test $test,
364
        PHPUnit\Framework\AssertionFailedError $e,
365
        float $time
366
    ): void {
367
        $this->lastFailureMessage = $this->composeMessage('FAILURE', $test, $e);
368
    }
369
370
    /**
371
     * A failure occurred.
372
     *
373
     * @param PHPUnit\Framework\Test $test
374
     * @param PHPUnit\Framework\AssertionFailedError $e
375
     * @param float $time
376
     */
377
    public function addWarning(PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, float $time): void
378
    {
379
        $this->lastWarningMessage = $this->composeMessage("WARNING", $test, $e);
380
    }
381
382
    /**
383
     * Incomplete test.
384
     *
385
     * @param PHPUnit\Framework\Test $test
386
     * @param Exception $e
387
     * @param float $time
388
     */
389
    public function addIncompleteTest(PHPUnit\Framework\Test $test, Throwable $e, float $time): void
390
    {
391
        $this->lastIncompleteMessage = $this->composeMessage("INCOMPLETE", $test, $e);
392
    }
393
394
    /**
395
     * Skipped test.
396
     *
397
     * @param PHPUnit\Framework\Test $test
398
     * @param Exception $e
399
     * @param float $time
400
     * @since Method available since Release 3.0.0
401
     */
402
    public function addSkippedTest(PHPUnit\Framework\Test $test, Throwable $e, float $time): void
403
    {
404
        $this->lastSkippedMessage = $this->composeMessage('SKIPPED', $test, $e);
405
    }
406
407
    /**
408
     * Risky test
409
     *
410
     * @param PHPUnit\Framework\Test $test
411
     * @param Throwable $e
412
     * @param float $time
413
     */
414
    public function addRiskyTest(PHPUnit\Framework\Test $test, Throwable $e, float $time): void
415
    {
416
        $this->lastRiskyMessage = $this->composeMessage('RISKY', $test, $e);
417
    }
418
419
    /**
420
     * A test suite started.
421
     *
422
     * @param PHPUnit\Framework\TestSuite $suite
423
     */
424
    public function startTestSuite(PHPUnit\Framework\TestSuite $suite): void
425
    {
426
    }
427
428
    /**
429
     * A test suite ended.
430
     *
431
     * @param PHPUnit\Framework\TestSuite $suite
432
     */
433
    public function endTestSuite(PHPUnit\Framework\TestSuite $suite): void
434
    {
435
    }
436
437
    /**
438
     * A test started.
439
     *
440
     * @param PHPUnit\Framework\Test $test
441
     */
442
    public function startTest(PHPUnit\Framework\Test $test): void
443
    {
444
    }
445
446
    /**
447
     * A test ended.
448
     *
449
     * @param PHPUnit\Framework\Test $test
450
     * @param float $time
451
     */
452
    public function endTest(PHPUnit\Framework\Test $test, float $time): void
453
    {
454
        if (($test instanceof PHPUnit\Framework\TestCase) && !$test->hasExpectationOnOutput()) {
455
            echo $test->getActualOutput();
456
        }
457
    }
458
459
    /**
460
     * Override to define how to handle a failed loading of
461
     * a test suite.
462
     *
463
     * @param  string $message
464
     * @throws BuildException
465
     */
466
    protected function runFailed($message): void
467
    {
468
        throw new BuildException($message);
469
    }
470
}
471