Passed
Push — master ( b8148a...2f69bc )
by Michiel
06:00
created

PHPUnitTestRunner9::getLastWarningMessage()   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
use Phing\Exception\BuildException;
21
use Phing\Io\IOException;
22
use Phing\Project;
23
24
/**
25
 * Simple Testrunner for PHPUnit that runs all tests of a testsuite.
26
 *
27
 * @author  Blair Cooper <[email protected]>
28
 * @package phing.tasks.ext.phpunit
29
 */
30
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

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

145
        /** @scrutinizer ignore-deprecated */ $res->addListener($this);

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...
146
147 4
        foreach ($this->formatters as $formatter) {
148 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

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