Passed
Push — master ( 045f45...2c73e4 )
by Michiel
08:31 queued 11s
created

PHPUnitTask::main()   D

Complexity

Conditions 14
Paths 281

Size

Total Lines 54
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 15.2919

Importance

Changes 0
Metric Value
cc 14
eloc 31
nc 281
nop 0
dl 0
loc 54
ccs 26
cts 32
cp 0.8125
crap 15.2919
rs 4.4208
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
 * Runs PHPUnit tests.
22
 *
23
 * @author  Michiel Rook <[email protected]>
24
 * @package phing.tasks.ext.phpunit
25
 * @see     BatchTest
26
 * @since   2.1.0
27
 */
28
class PHPUnitTask extends Task
29
{
30
    private $batchtests = [];
31
    /**
32
     * @var FormatterElement[] $formatters
33
     */
34
    private $formatters = [];
35
    private $bootstrap = "";
36
    private $haltonerror = false;
37
    private $haltonfailure = false;
38
    private $haltonincomplete = false;
39
    private $haltonskipped = false;
40
    private $errorproperty;
41
    private $failureproperty;
42
    private $incompleteproperty;
43
    private $skippedproperty;
44
    private $printsummary = false;
45
    private $testfailed = false;
46
    private $testfailuremessage = "";
47
    private $codecoverage = null;
48
    private $groups = [];
49
    private $excludeGroups = [];
50
    private $processIsolation = false;
51
    private $usecustomerrorhandler = true;
52
    private $listeners = [];
53
54
    /**
55
     * @var string
56
     */
57
    private $pharLocation = "";
58
59
    /**
60
     * @var PhingFile
61
     */
62
    private $configuration = null;
63
64
    /**
65
     * Initialize Task.
66
     * This method includes any necessary PHPUnit libraries and triggers
67
     * appropriate error if they cannot be found.  This is not done in header
68
     * because we may want this class to be loaded w/o triggering an error.
69
     */
70 4
    public function init()
71
    {
72 4
    }
73
74 4
    private function loadPHPUnit()
75
    {
76
        /**
77
         * Determine PHPUnit version number, try
78
         * PEAR old-style, then composer, then PHAR
79
         */
80 4
        @include_once 'PHPUnit/Runner/Version.php';
81 4
        if (!class_exists('PHPUnit_Runner_Version')) {
82 4
            @include_once 'phpunit/Runner/Version.php';
83
        }
84 4
        if (!empty($this->pharLocation)) {
85
            $GLOBALS['_SERVER']['SCRIPT_NAME'] = '-';
86
            ob_start();
87
            @include $this->pharLocation;
88
            ob_end_clean();
89
        }
90
91 4
        @include_once 'PHPUnit/Autoload.php';
92 4
        if (!class_exists('PHPUnit\Runner\Version')) {
93
            throw new BuildException("PHPUnitTask requires PHPUnit to be installed", $this->getLocation());
94
        }
95 4
    }
96
97
    /**
98
     * Sets the name of a bootstrap file that is run before
99
     * executing the tests
100
     *
101
     * @param string $bootstrap the name of the bootstrap file
102
     */
103 1
    public function setBootstrap($bootstrap)
104
    {
105 1
        $this->bootstrap = $bootstrap;
106 1
    }
107
108
    /**
109
     * @param $value
110
     */
111
    public function setErrorproperty($value)
112
    {
113
        $this->errorproperty = $value;
114
    }
115
116
    /**
117
     * @param $value
118
     */
119
    public function setFailureproperty($value)
120
    {
121
        $this->failureproperty = $value;
122
    }
123
124
    /**
125
     * @param $value
126
     */
127
    public function setIncompleteproperty($value)
128
    {
129
        $this->incompleteproperty = $value;
130
    }
131
132
    /**
133
     * @param $value
134
     */
135
    public function setSkippedproperty($value)
136
    {
137
        $this->skippedproperty = $value;
138
    }
139
140
    /**
141
     * @param $value
142
     */
143 3
    public function setHaltonerror($value)
144
    {
145 3
        $this->haltonerror = $value;
146 3
    }
147
148
    /**
149
     * @param $value
150
     */
151 3
    public function setHaltonfailure($value)
152
    {
153 3
        $this->haltonfailure = $value;
154 3
    }
155
156
    /**
157
     * @return bool
158
     */
159
    public function getHaltonfailure()
160
    {
161
        return $this->haltonfailure;
162
    }
163
164
    /**
165
     * @param $value
166
     */
167
    public function setHaltonincomplete($value)
168
    {
169
        $this->haltonincomplete = $value;
170
    }
171
172
    /**
173
     * @return bool
174
     */
175 1
    public function getHaltonincomplete()
176
    {
177 1
        return $this->haltonincomplete;
178
    }
179
180
    /**
181
     * @param $value
182
     */
183
    public function setHaltonskipped($value)
184
    {
185
        $this->haltonskipped = $value;
186
    }
187
188
    /**
189
     * @return bool
190
     */
191 1
    public function getHaltonskipped()
192
    {
193 1
        return $this->haltonskipped;
194
    }
195
196
    /**
197
     * @param $printsummary
198
     */
199 1
    public function setPrintsummary($printsummary)
200
    {
201 1
        $this->printsummary = $printsummary;
202 1
    }
203
204
    /**
205
     * @param $codecoverage
206
     */
207 1
    public function setCodecoverage($codecoverage)
208
    {
209 1
        $this->codecoverage = $codecoverage;
210 1
    }
211
212
    /**
213
     * @param $processIsolation
214
     */
215
    public function setProcessIsolation($processIsolation)
216
    {
217
        $this->processIsolation = $processIsolation;
218
    }
219
220
    /**
221
     * @param $usecustomerrorhandler
222
     */
223
    public function setUseCustomErrorHandler($usecustomerrorhandler)
224
    {
225
        $this->usecustomerrorhandler = $usecustomerrorhandler;
226
    }
227
228
    /**
229
     * @param $groups
230
     */
231
    public function setGroups($groups)
232
    {
233
        $token = ' ,;';
234
        $this->groups = [];
235
        $tok = strtok($groups, $token);
236
        while ($tok !== false) {
237
            $this->groups[] = $tok;
238
            $tok = strtok($token);
239
        }
240
    }
241
242
    /**
243
     * @param $excludeGroups
244
     */
245
    public function setExcludeGroups($excludeGroups)
246
    {
247
        $token = ' ,;';
248
        $this->excludeGroups = [];
249
        $tok = strtok($excludeGroups, $token);
250
        while ($tok !== false) {
251
            $this->excludeGroups[] = $tok;
252
            $tok = strtok($token);
253
        }
254
    }
255
256
    /**
257
     * Add a new formatter to all tests of this task.
258
     *
259
     * @param FormatterElement $fe formatter element
260
     */
261 2
    public function addFormatter(FormatterElement $fe)
262
    {
263 2
        $fe->setParent($this);
264 2
        $this->formatters[] = $fe;
265 2
    }
266
267
    /**
268
     * Add a new listener to all tests of this taks
269
     *
270
     * @param $listener
271
     */
272
    private function addListener($listener)
273
    {
274
        $this->listeners[] = $listener;
275
    }
276
277
    /**
278
     * @param PhingFile $configuration
279
     */
280
    public function setConfiguration(PhingFile $configuration)
281
    {
282
        $this->configuration = $configuration;
283
    }
284
285
    /**
286
     * @param string $pharLocation
287
     */
288
    public function setPharLocation($pharLocation)
289
    {
290
        $this->pharLocation = $pharLocation;
291
    }
292
293
    /**
294
     * Load and processes the PHPUnit configuration
295
     *
296
     * @param  $configuration
297
     * @return array
298
     * @throws ReflectionException
299
     * @throws BuildException
300
     */
301
    protected function handlePHPUnitConfiguration(PhingFile $configuration)
302
    {
303
        if (!$configuration->exists()) {
304
            throw new BuildException("Unable to find PHPUnit configuration file '" . (string) $configuration . "'");
305
        }
306
307
        $config = \PHPUnit\Util\Configuration::getInstance($configuration->getAbsolutePath());
308
309
        if (empty($config)) {
310
            return [];
311
        }
312
313
        $phpunit = $config->getPHPUnitConfiguration();
314
315
        if (empty($phpunit)) {
316
            return [];
317
        }
318
319
        $config->handlePHPConfiguration();
320
321
        if (isset($phpunit['bootstrap'])) {
322
            $this->setBootstrap($phpunit['bootstrap']);
323
        }
324
325
        if (isset($phpunit['stopOnFailure'])) {
326
            $this->setHaltonfailure($phpunit['stopOnFailure']);
327
        }
328
329
        if (isset($phpunit['stopOnError'])) {
330
            $this->setHaltonerror($phpunit['stopOnError']);
331
        }
332
333
        if (isset($phpunit['stopOnSkipped'])) {
334
            $this->setHaltonskipped($phpunit['stopOnSkipped']);
335
        }
336
337
        if (isset($phpunit['stopOnIncomplete'])) {
338
            $this->setHaltonincomplete($phpunit['stopOnIncomplete']);
339
        }
340
341
        if (isset($phpunit['processIsolation'])) {
342
            $this->setProcessIsolation($phpunit['processIsolation']);
343
        }
344
345
        foreach ($config->getListenerConfiguration() as $listener) {
346
            if (!class_exists($listener['class'], false)
347
                && $listener['file'] !== ''
348
            ) {
349
                include_once $listener['file'];
350
            }
351
352
            if (class_exists($listener['class'])) {
353
                if (count($listener['arguments']) == 0) {
354
                    $listener = new $listener['class']();
355
                } else {
356
                    $listenerClass = new ReflectionClass(
357
                        $listener['class']
358
                    );
359
                    $listener = $listenerClass->newInstanceArgs(
360
                        $listener['arguments']
361
                    );
362
                }
363
364
                if ($listener instanceof \PHPUnit\Framework\TestListener) {
365
                    $this->addListener($listener);
366
                }
367
            }
368
        }
369
370
        if (method_exists($config, 'getSeleniumBrowserConfiguration')) {
371
            $browsers = $config->getSeleniumBrowserConfiguration();
372
373
            if (!empty($browsers)
374
                && class_exists('PHPUnit_Extensions_SeleniumTestCase')
375
            ) {
376
                PHPUnit_Extensions_SeleniumTestCase::$browsers = $browsers;
0 ignored issues
show
Bug introduced by
The type PHPUnit_Extensions_SeleniumTestCase was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
377
            }
378
        }
379
380
        return $phpunit;
381
    }
382
383
    /**
384
     * The main entry point
385
     *
386
     * @throws BuildException
387
     */
388 4
    public function main()
389
    {
390 4
        if ($this->codecoverage && !extension_loaded('xdebug')) {
391
            throw new BuildException("PHPUnitTask depends on Xdebug being installed to gather code coverage information.");
392
        }
393
394 4
        $this->loadPHPUnit();
395 4
        $suite = new \PHPUnit\Framework\TestSuite('AllTests');
396 4
        $autoloadSave = spl_autoload_functions();
397
398 4
        if ($this->bootstrap) {
399 1
            include $this->bootstrap;
400
        }
401
402 4
        if ($this->configuration) {
403
            $arguments = $this->handlePHPUnitConfiguration($this->configuration);
404
405
            if ($arguments['backupGlobals'] === false) {
406
                $suite->setBackupGlobals(false);
407
            }
408
409
            if ($arguments['backupStaticAttributes'] === true) {
410
                $suite->setBackupStaticAttributes(true);
411
            }
412
        }
413
414 4
        if ($this->printsummary) {
415 1
            $fe = new FormatterElement();
416 1
            $fe->setParent($this);
417 1
            $fe->setType("summary");
418 1
            $fe->setUseFile(false);
419 1
            $this->formatters[] = $fe;
420
        }
421
422 4
        foreach ($this->batchtests as $batchTest) {
423 4
            $this->appendBatchTestToTestSuite($batchTest, $suite);
424
        }
425
426 4
        $this->execute($suite);
427
428 4
        if ($this->testfailed) {
429 1
            throw new BuildException($this->testfailuremessage);
430
        }
431
432 3
        $autoloadNew = spl_autoload_functions();
433 3
        if (is_array($autoloadNew)) {
0 ignored issues
show
introduced by
The condition is_array($autoloadNew) is always true.
Loading history...
434 3
            foreach ($autoloadNew as $autoload) {
435 3
                spl_autoload_unregister($autoload);
436
            }
437
        }
438
439 3
        if (is_array($autoloadSave)) {
440 3
            foreach ($autoloadSave as $autoload) {
441 3
                spl_autoload_register($autoload);
442
            }
443
        }
444 3
    }
445
446
    /**
447
     * @param $suite
448
     * @throws BuildException
449
     * @throws ReflectionException
450
     */
451 4
    protected function execute($suite)
452
    {
453 4
        if (class_exists('\PHPUnit\Runner\Version', false) && version_compare(
454 4
            \PHPUnit\Runner\Version::id(),
455 4
            '8.0.0',
456 4
            '<'
457
        )) {
458 4
            $runner = new PHPUnitTestRunner7(
459 4
                $this->project,
460 4
                $this->groups,
461 4
                $this->excludeGroups,
462 4
                $this->processIsolation
463
            );
464
        } else {
465
            $runner = new PHPUnitTestRunner8(
466
                $this->project,
467
                $this->groups,
468
                $this->excludeGroups,
469
                $this->processIsolation
470
            );
471
        }
472
473 4
        if ($this->codecoverage) {
474
            /**
475
             * Add some defaults to the PHPUnit filter
476
             */
477
            $pwd = __DIR__;
478
            $path = realpath($pwd . '/../../../');
479
480
            if (class_exists('\SebastianBergmann\CodeCoverage\Filter')) {
481
                $filter = new \SebastianBergmann\CodeCoverage\Filter();
482
                if (method_exists($filter, 'addDirectoryToBlacklist')) {
483
                    $filter->addDirectoryToBlacklist($path);
484
                }
485
                if (class_exists('\SebastianBergmann\CodeCoverage\CodeCoverage')) {
486
                    $codeCoverage = new \SebastianBergmann\CodeCoverage\CodeCoverage(null, $filter);
487
                    $runner->setCodecoverage($codeCoverage);
488
                }
489
            }
490
        }
491
492 4
        $runner->setUseCustomErrorHandler($this->usecustomerrorhandler);
493
494 4
        foreach ($this->listeners as $listener) {
495
            $runner->addListener($listener);
496
        }
497
498 4
        foreach ($this->formatters as $fe) {
499 2
            $formatter = $fe->getFormatter();
500
501 2
            if ($fe->getUseFile()) {
502
                try {
503
                    $destFile = new PhingFile($fe->getToDir(), $fe->getOutfile());
504
                } catch (Exception $e) {
505
                    throw new BuildException('Unable to create destination.', $e);
506
                }
507
508
                $writer = new FileWriter($destFile->getAbsolutePath());
509
510
                $formatter->setOutput($writer);
511
            } else {
512 2
                $formatter->setOutput($this->getDefaultOutput());
513
            }
514
515 2
            $runner->addFormatter($formatter);
516
517 2
            $formatter->startTestRun();
518
        }
519
520 4
        $runner->run($suite);
521
522 4
        foreach ($this->formatters as $fe) {
523 2
            $formatter = $fe->getFormatter();
524 2
            $formatter->endTestRun();
525
        }
526
527 4
        if ($runner->hasErrors()) {
528 2
            if ($this->errorproperty) {
529
                $this->project->setNewProperty($this->errorproperty, true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type string expected by parameter $value of Project::setNewProperty(). ( Ignorable by Annotation )

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

529
                $this->project->setNewProperty($this->errorproperty, /** @scrutinizer ignore-type */ true);
Loading history...
530
            }
531 2
            if ($this->haltonerror) {
532
                $this->testfailed = true;
533
                $this->testfailuremessage = $runner->getLastErrorMessage();
534
            }
535
        }
536
537 4
        if ($runner->hasFailures()) {
538 3
            if ($this->failureproperty) {
539
                $this->project->setNewProperty($this->failureproperty, true);
540
            }
541
542 3
            if ($this->haltonfailure) {
543 1
                $this->testfailed = true;
544 1
                $this->testfailuremessage = $runner->getLastFailureMessage();
545
            }
546
        }
547
548 4
        if ($runner->hasIncomplete()) {
549
            if ($this->incompleteproperty) {
550
                $this->project->setNewProperty($this->incompleteproperty, true);
551
            }
552
553
            if ($this->haltonincomplete) {
554
                $this->testfailed = true;
555
                $this->testfailuremessage = $runner->getLastIncompleteMessage();
556
            }
557
        }
558
559 4
        if ($runner->hasSkipped()) {
560
            if ($this->skippedproperty) {
561
                $this->project->setNewProperty($this->skippedproperty, true);
562
            }
563
564
            if ($this->haltonskipped) {
565
                $this->testfailed = true;
566
                $this->testfailuremessage = $runner->getLastSkippedMessage();
567
            }
568
        }
569 4
    }
570
571
    /**
572
     * Add the tests in this batchtest to a test suite
573
     *
574
     * @param BatchTest $batchTest
575
     * @param PHPUnit\Framework\TestSuite $suite
576
     * @throws BuildException
577
     * @throws ReflectionException
578
     */
579 4
    protected function appendBatchTestToTestSuite(BatchTest $batchTest, $suite)
580
    {
581 4
        foreach ($batchTest->elements() as $element) {
582 4
            $testClass = new $element();
583 4
            if (!($testClass instanceof PHPUnit\Framework\TestSuite)) {
584 4
                $testClass = new ReflectionClass($element);
585
            }
586
            try {
587 4
                $suite->addTestSuite($testClass);
588
            } catch (\PHPUnit\Framework\Exception $e) {
589 4
                throw new BuildException('Unable to add TestSuite ' . get_class($testClass), $e);
590
            }
591
        }
592 4
    }
593
594
    /**
595
     * @return LogWriter
596
     */
597 2
    protected function getDefaultOutput()
598
    {
599 2
        return new LogWriter($this);
600
    }
601
602
    /**
603
     * Adds a set of tests based on pattern matching.
604
     *
605
     * @return BatchTest a new instance of a batch test.
606
     */
607 4
    public function createBatchTest()
608
    {
609 4
        $batchtest = new BatchTest($this->getProject());
610
611 4
        $this->batchtests[] = $batchtest;
612
613 4
        return $batchtest;
614
    }
615
}
616