Passed
Push — master ( 1f4a7c...6f18ed )
by Siad
11:10
created

PHPUnitTask::setWarningproperty()   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 1
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
 * 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 $haltondefect = false;
41
    private $haltonwarning = false;
42
    private $haltonrisky = false;
43
    private $errorproperty;
44
    private $failureproperty;
45
    private $incompleteproperty;
46
    private $skippedproperty;
47
    private $warningproperty;
48
    private $riskyproperty;
49
    private $printsummary = false;
50
    private $testfailed = false;
51
    private $testfailuremessage = "";
52
    private $codecoverage = null;
53
    private $groups = [];
54
    private $excludeGroups = [];
55
    private $processIsolation = false;
56
    private $usecustomerrorhandler = true;
57
    private $listeners = [];
58
59
    /**
60
     * @var string
61
     */
62
    private $pharLocation = "";
63
64
    /**
65
     * @var PhingFile
66
     */
67
    private $configuration = null;
68
69
    /**
70
     * Initialize Task.
71
     * This method includes any necessary PHPUnit libraries and triggers
72
     * appropriate error if they cannot be found.  This is not done in header
73
     * because we may want this class to be loaded w/o triggering an error.
74
     */
75 4
    public function init()
76
    {
77 4
    }
78
79 4
    private function loadPHPUnit()
80
    {
81
        /**
82
         * Determine PHPUnit version number, try
83
         * PEAR old-style, then composer, then PHAR
84
         */
85 4
        @include_once 'PHPUnit/Runner/Version.php';
86 4
        if (!class_exists('PHPUnit_Runner_Version')) {
87 4
            @include_once 'phpunit/Runner/Version.php';
88
        }
89 4
        if (!empty($this->pharLocation)) {
90
            $GLOBALS['_SERVER']['SCRIPT_NAME'] = '-';
91
            ob_start();
92
            @include $this->pharLocation;
93
            ob_end_clean();
94
        }
95
96 4
        @include_once 'PHPUnit/Autoload.php';
97 4
        if (!class_exists('PHPUnit\Runner\Version')) {
98
            throw new BuildException("PHPUnitTask requires PHPUnit to be installed", $this->getLocation());
99
        }
100 4
    }
101
102
    /**
103
     * Sets the name of a bootstrap file that is run before
104
     * executing the tests
105
     *
106
     * @param string $bootstrap the name of the bootstrap file
107
     */
108 1
    public function setBootstrap($bootstrap)
109
    {
110 1
        $this->bootstrap = $bootstrap;
111 1
    }
112
113
    /**
114
     * @param $value
115
     */
116
    public function setErrorproperty($value)
117
    {
118
        $this->errorproperty = $value;
119
    }
120
121
    /**
122
     * @param $value
123
     */
124
    public function setFailureproperty($value)
125
    {
126
        $this->failureproperty = $value;
127
    }
128
129
    /**
130
     * @param $value
131
     */
132
    public function setIncompleteproperty($value)
133
    {
134
        $this->incompleteproperty = $value;
135
    }
136
137
    /**
138
     * @param $value
139
     */
140
    public function setSkippedproperty($value)
141
    {
142
        $this->skippedproperty = $value;
143
    }
144
145
    /**
146
     * @param $value
147
     */
148
    public function setRiskyproperty($value)
149
    {
150
        $this->riskyproperty = $value;
151
    }
152
153
    /**
154
     * @param $value
155
     */
156
    public function setWarningproperty($value)
157
    {
158
        $this->riskyproperty = $value;
159
    }
160
161
    /**
162
     * @return bool
163
     */
164
    public function getHaltondefect(): bool
165
    {
166
        return $this->haltondefect;
167
    }
168
169
    /**
170
     * @param bool $haltondefect
171
     */
172
    public function setHaltondefect(bool $haltondefect): void
173
    {
174
        $this->haltondefect = $haltondefect;
175
    }
176
177
    /**
178
     * @return bool
179
     */
180
    public function getHaltonwarning(): bool
181
    {
182
        return $this->haltonwarning;
183
    }
184
185
    /**
186
     * @param bool $haltonwarning
187
     */
188
    public function setHaltonwarning(bool $haltonwarning): void
189
    {
190
        $this->haltonwarning = $haltonwarning;
191
    }
192
193
    /**
194
     * @return bool
195
     */
196
    public function getHaltonrisky(): bool
197
    {
198
        return $this->haltonrisky;
199
    }
200
201
    /**
202
     * @param bool $haltonrisky
203
     */
204
    public function setHaltonrisky(bool $haltonrisky): void
205
    {
206
        $this->haltonrisky = $haltonrisky;
207
    }
208
209
    /**
210
     * @param $value
211
     */
212 3
    public function setHaltonerror($value)
213
    {
214 3
        $this->haltonerror = $value;
215 3
    }
216
217
    /**
218
     * @param $value
219
     */
220 3
    public function setHaltonfailure($value)
221
    {
222 3
        $this->haltonfailure = $value;
223 3
    }
224
225
    /**
226
     * @return bool
227
     */
228
    public function getHaltonfailure()
229
    {
230
        return $this->haltonfailure;
231
    }
232
233
    /**
234
     * @param $value
235
     */
236
    public function setHaltonincomplete($value)
237
    {
238
        $this->haltonincomplete = $value;
239
    }
240
241
    /**
242
     * @return bool
243
     */
244 1
    public function getHaltonincomplete()
245
    {
246 1
        return $this->haltonincomplete;
247
    }
248
249
    /**
250
     * @param $value
251
     */
252
    public function setHaltonskipped($value)
253
    {
254
        $this->haltonskipped = $value;
255
    }
256
257
    /**
258
     * @return bool
259
     */
260 1
    public function getHaltonskipped()
261
    {
262 1
        return $this->haltonskipped;
263
    }
264
265
    /**
266
     * @param $printsummary
267
     */
268 1
    public function setPrintsummary($printsummary)
269
    {
270 1
        $this->printsummary = $printsummary;
271 1
    }
272
273
    /**
274
     * @param $codecoverage
275
     */
276 1
    public function setCodecoverage($codecoverage)
277
    {
278 1
        $this->codecoverage = $codecoverage;
279 1
    }
280
281
    /**
282
     * @param $processIsolation
283
     */
284
    public function setProcessIsolation($processIsolation)
285
    {
286
        $this->processIsolation = $processIsolation;
287
    }
288
289
    /**
290
     * @param $usecustomerrorhandler
291
     */
292
    public function setUseCustomErrorHandler($usecustomerrorhandler)
293
    {
294
        $this->usecustomerrorhandler = $usecustomerrorhandler;
295
    }
296
297
    /**
298
     * @param $groups
299
     */
300
    public function setGroups($groups)
301
    {
302
        $token = ' ,;';
303
        $this->groups = [];
304
        $tok = strtok($groups, $token);
305
        while ($tok !== false) {
306
            $this->groups[] = $tok;
307
            $tok = strtok($token);
308
        }
309
    }
310
311
    /**
312
     * @param $excludeGroups
313
     */
314
    public function setExcludeGroups($excludeGroups)
315
    {
316
        $token = ' ,;';
317
        $this->excludeGroups = [];
318
        $tok = strtok($excludeGroups, $token);
319
        while ($tok !== false) {
320
            $this->excludeGroups[] = $tok;
321
            $tok = strtok($token);
322
        }
323
    }
324
325
    /**
326
     * Add a new formatter to all tests of this task.
327
     *
328
     * @param FormatterElement $fe formatter element
329
     */
330 2
    public function addFormatter(FormatterElement $fe)
331
    {
332 2
        $fe->setParent($this);
333 2
        $this->formatters[] = $fe;
334 2
    }
335
336
    /**
337
     * Add a new listener to all tests of this taks
338
     *
339
     * @param $listener
340
     */
341
    private function addListener($listener)
342
    {
343
        $this->listeners[] = $listener;
344
    }
345
346
    /**
347
     * @param PhingFile $configuration
348
     */
349
    public function setConfiguration(PhingFile $configuration)
350
    {
351
        $this->configuration = $configuration;
352
    }
353
354
    /**
355
     * @param string $pharLocation
356
     */
357
    public function setPharLocation($pharLocation)
358
    {
359
        $this->pharLocation = $pharLocation;
360
    }
361
362
    /**
363
     * Load and processes the PHPUnit configuration
364
     *
365
     * @param  $configuration
366
     * @return mixed
367
     * @throws ReflectionException
368
     * @throws BuildException
369
     */
370
    protected function handlePHPUnitConfiguration(PhingFile $configuration)
371
    {
372
        if (!$configuration->exists()) {
373
            throw new BuildException("Unable to find PHPUnit configuration file '" . (string) $configuration . "'");
374
        }
375
376
        if (class_exists('\PHPUnit\TextUI\Configuration\Registry')) {
377
            $config = \PHPUnit\TextUI\Configuration\Registry::getInstance()->get($configuration->getAbsolutePath());
0 ignored issues
show
Bug introduced by
The type PHPUnit\TextUI\Configuration\Registry 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...
378
        } elseif (class_exists('\PHPUnit\TextUI\XmlConfiguration\Loader')) {
379
            $config = (new \PHPUnit\TextUI\XmlConfiguration\Loader())->load($configuration->getAbsolutePath());
380
        } else {
381
            throw new BuildException("Can't parse PHPUnit configuration file '" . (string) $configuration . "'");
382
        }
383
384
        if (empty($config)) {
385
            return [];
386
        }
387
388
        $phpunit = $config->phpunit();
389
390
        if (empty($phpunit)) {
391
            return [];
392
        }
393
394
        if ($phpunit->hasBootstrap()) {
395
            $this->setBootstrap($phpunit->bootstrap());
396
        }
397
        $this->setHaltonfailure($phpunit->stopOnFailure());
398
        $this->setHaltonerror($phpunit->stopOnError());
399
        $this->setHaltonskipped($phpunit->stopOnSkipped());
400
        $this->setHaltonincomplete($phpunit->stopOnIncomplete());
401
        $this->setHaltondefect($phpunit->stopOnDefect());
402
        $this->setHaltonwarning($phpunit->stopOnWarning());
403
        $this->setHaltonrisky($phpunit->stopOnRisky());
404
        $this->setProcessIsolation($phpunit->processIsolation());
405
406
        foreach ($config->listeners() as $listener) {
407
            if (
408
                !class_exists($listener->className(), false)
409
                && $listener->hasSourceFile()
410
            ) {
411
                include_once $listener->sourceFile();
412
            }
413
414
            if (class_exists($listener->className())) {
415
                if ($listener->hasArguments()) {
416
                    $listener = (new $listener->className())();
417
                } else {
418
                    $listenerClass = new ReflectionClass(
419
                        $listener->className()
420
                    );
421
                    $listener = $listenerClass->newInstanceArgs(
422
                        $listener->arguments()
423
                    );
424
                }
425
426
                if ($listener instanceof \PHPUnit\Framework\TestListener) {
427
                    $this->addListener($listener);
428
                }
429
            }
430
        }
431
432
        return $phpunit;
433
    }
434
435
    /**
436
     * The main entry point
437
     *
438
     * @throws BuildException
439
     */
440 4
    public function main()
441
    {
442 4
        if ($this->codecoverage && !extension_loaded('xdebug')) {
443
            throw new BuildException("PHPUnitTask depends on Xdebug being installed to gather code coverage information.");
444
        }
445
446 4
        $this->loadPHPUnit();
447 4
        $suite = new \PHPUnit\Framework\TestSuite('AllTests');
448 4
        $autoloadSave = spl_autoload_functions();
449
450 4
        if ($this->bootstrap) {
451 1
            include $this->bootstrap;
452
        }
453
454 4
        if ($this->configuration) {
455
            $phpunit = $this->handlePHPUnitConfiguration($this->configuration);
456
457
            if ($phpunit->backupGlobals() === false) {
458
                $suite->setBackupGlobals(false);
459
            }
460
461
            if ($phpunit->backupStaticAttributes() === true) {
462
                $suite->setBackupStaticAttributes(true);
463
            }
464
        }
465
466 4
        if ($this->printsummary) {
467 1
            $fe = new FormatterElement();
468 1
            $fe->setParent($this);
469 1
            $fe->setType("summary");
470 1
            $fe->setUseFile(false);
471 1
            $this->formatters[] = $fe;
472
        }
473
474 4
        foreach ($this->batchtests as $batchTest) {
475 4
            $this->appendBatchTestToTestSuite($batchTest, $suite);
476
        }
477
478 4
        $this->execute($suite);
479
480 4
        if ($this->testfailed) {
481 1
            throw new BuildException($this->testfailuremessage);
482
        }
483
484 3
        $autoloadNew = spl_autoload_functions();
485 3
        if (is_array($autoloadNew)) {
0 ignored issues
show
introduced by
The condition is_array($autoloadNew) is always true.
Loading history...
486 3
            foreach ($autoloadNew as $autoload) {
487 3
                spl_autoload_unregister($autoload);
488
            }
489
        }
490
491 3
        if (is_array($autoloadSave)) {
492 3
            foreach ($autoloadSave as $autoload) {
493 3
                spl_autoload_register($autoload);
494
            }
495
        }
496 3
    }
497
498
    /**
499
     * @param $suite
500
     * @throws BuildException
501
     * @throws ReflectionException
502
     */
503 4
    protected function execute($suite)
504
    {
505
        if (
506 4
            class_exists('\PHPUnit\Runner\Version', false) &&
507 4
            version_compare(\PHPUnit\Runner\Version::id(), '8.0.0', '<')
508
        ) {
509
            $runner = new PHPUnitTestRunner7(
510
                $this->project,
511
                $this->groups,
512
                $this->excludeGroups,
513
                $this->processIsolation
514
            );
515
        } else {
516 4
            $runner = new PHPUnitTestRunner8(
517 4
                $this->project,
518 4
                $this->groups,
519 4
                $this->excludeGroups,
520 4
                $this->processIsolation
521
            );
522
        }
523
524 4
        if ($this->codecoverage) {
525
            /**
526
             * Add some defaults to the PHPUnit filter
527
             */
528
            $pwd = __DIR__;
529
            $path = realpath($pwd . '/../../../');
530
531
            if (class_exists('\SebastianBergmann\CodeCoverage\Filter')) {
532
                $filter = new \SebastianBergmann\CodeCoverage\Filter();
533
                if (method_exists($filter, 'addDirectoryToBlacklist')) {
534
                    $filter->addDirectoryToBlacklist($path);
535
                }
536
                if (class_exists('\SebastianBergmann\CodeCoverage\CodeCoverage')) {
537
                    $driver = (new \SebastianBergmann\CodeCoverage\Driver\Selector())->forLineCoverage($filter);
538
                    $codeCoverage = new \SebastianBergmann\CodeCoverage\CodeCoverage($driver, $filter);
539
                    $runner->setCodecoverage($codeCoverage);
540
                }
541
            }
542
        }
543
544 4
        $runner->setUseCustomErrorHandler($this->usecustomerrorhandler);
545
546 4
        foreach ($this->listeners as $listener) {
547
            $runner->addListener($listener);
548
        }
549
550 4
        foreach ($this->formatters as $fe) {
551 2
            $formatter = $fe->getFormatter();
552
553 2
            if ($fe->getUseFile()) {
554
                try {
555
                    $destFile = new PhingFile($fe->getToDir(), $fe->getOutfile());
556
                } catch (Exception $e) {
557
                    throw new BuildException('Unable to create destination.', $e);
558
                }
559
560
                $writer = new FileWriter($destFile->getAbsolutePath());
561
562
                $formatter->setOutput($writer);
563
            } else {
564 2
                $formatter->setOutput($this->getDefaultOutput());
565
            }
566
567 2
            $runner->addFormatter($formatter);
568
569 2
            $formatter->startTestRun();
570
        }
571
572 4
        $runner->run($suite);
573
574 4
        foreach ($this->formatters as $fe) {
575 2
            $formatter = $fe->getFormatter();
576 2
            $formatter->endTestRun();
577
        }
578
579 4
        if ($runner->hasErrors()) {
580 2
            if ($this->errorproperty) {
581
                $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

581
                $this->project->setNewProperty($this->errorproperty, /** @scrutinizer ignore-type */ true);
Loading history...
582
            }
583 2
            if ($this->haltonerror) {
584
                $this->testfailed = true;
585
                $this->testfailuremessage = $runner->getLastErrorMessage();
586
            }
587
        }
588
589 4
        if ($runner->hasFailures()) {
590 3
            if ($this->failureproperty) {
591
                $this->project->setNewProperty($this->failureproperty, true);
592
            }
593
594 3
            if ($this->haltonfailure) {
595 1
                $this->testfailed = true;
596 1
                $this->testfailuremessage = $runner->getLastFailureMessage();
597
            }
598
        }
599
600 4
        if ($runner->hasIncomplete()) {
601
            if ($this->incompleteproperty) {
602
                $this->project->setNewProperty($this->incompleteproperty, true);
603
            }
604
605
            if ($this->haltonincomplete) {
606
                $this->testfailed = true;
607
                $this->testfailuremessage = $runner->getLastIncompleteMessage();
608
            }
609
        }
610
611 4
        if ($runner->hasSkipped()) {
612
            if ($this->skippedproperty) {
613
                $this->project->setNewProperty($this->skippedproperty, true);
614
            }
615
616
            if ($this->haltonskipped) {
617
                $this->testfailed = true;
618
                $this->testfailuremessage = $runner->getLastSkippedMessage();
619
            }
620
        }
621
622 4
        if ($runner->hasWarnings()) {
623
            if ($this->warningproperty) {
624
                $this->project->setNewProperty($this->warningproperty, true);
625
            }
626
627
            if ($this->haltonwarning) {
628
                $this->testfailed = true;
629
                $this->testfailuremessage = $runner->getLastWarningMessage();
630
            }
631
        }
632
633 4
        if ($runner->hasRisky()) {
634
            if ($this->riskyproperty) {
635
                $this->project->setNewProperty($this->riskyproperty, true);
636
            }
637
638
            if ($this->haltonrisky) {
639
                $this->testfailed = true;
640
                $this->testfailuremessage = $runner->getLastRiskyMessage();
641
            }
642
        }
643 4
    }
644
645
    /**
646
     * Add the tests in this batchtest to a test suite
647
     *
648
     * @param BatchTest $batchTest
649
     * @param PHPUnit\Framework\TestSuite $suite
650
     * @throws BuildException
651
     * @throws ReflectionException
652
     */
653 4
    protected function appendBatchTestToTestSuite(BatchTest $batchTest, $suite)
654
    {
655 4
        foreach ($batchTest->elements() as $element) {
656 4
            $testClass = new $element();
657 4
            if (!($testClass instanceof PHPUnit\Framework\TestSuite)) {
658 4
                $testClass = new ReflectionClass($element);
659
            }
660
            try {
661 4
                $suite->addTestSuite($testClass);
662
            } catch (\PHPUnit\Framework\Exception $e) {
663
                throw new BuildException('Unable to add TestSuite ' . get_class($testClass), $e);
664
            }
665
        }
666 4
    }
667
668
    /**
669
     * @return LogWriter
670
     */
671 2
    protected function getDefaultOutput()
672
    {
673 2
        return new LogWriter($this);
674
    }
675
676
    /**
677
     * Adds a set of tests based on pattern matching.
678
     *
679
     * @return BatchTest a new instance of a batch test.
680
     */
681 4
    public function createBatchTest()
682
    {
683 4
        $batchtest = new BatchTest($this->getProject());
684
685 4
        $this->batchtests[] = $batchtest;
686
687 4
        return $batchtest;
688
    }
689
}
690