Completed
Push — master ( 01e071...007090 )
by Ehsan
01:46 queued 13s
created

Configuration::getPHPUnitConfiguration()   F

Complexity

Conditions 44
Paths > 20000

Size

Total Lines 298
Code Lines 165

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 44
eloc 165
nc 4294967295
nop 0
dl 0
loc 298
rs 2
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 file is part of PHPUnit.
4
 *
5
 * (c) Sebastian Bergmann <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace PHPUnit\Util;
11
12
use DOMElement;
13
use DOMXPath;
14
use File_Iterator_Facade;
15
use PHPUnit\Framework\Exception;
16
use PHPUnit\Framework\TestSuite;
17
use PHPUnit\TextUI\ResultPrinter;
18
19
/**
20
 * Wrapper for the PHPUnit XML configuration file.
21
 *
22
 * Example XML configuration file:
23
 * <code>
24
 * <?xml version="1.0" encoding="utf-8" ?>
25
 *
26
 * <phpunit backupGlobals="false"
27
 *          backupStaticAttributes="false"
28
 *          bootstrap="/path/to/bootstrap.php"
29
 *          cacheTokens="false"
30
 *          columns="80"
31
 *          colors="false"
32
 *          stderr="false"
33
 *          convertErrorsToExceptions="true"
34
 *          convertNoticesToExceptions="true"
35
 *          convertWarningsToExceptions="true"
36
 *          forceCoversAnnotation="false"
37
 *          processIsolation="false"
38
 *          stopOnError="false"
39
 *          stopOnFailure="false"
40
 *          stopOnWarning="false"
41
 *          stopOnIncomplete="false"
42
 *          stopOnRisky="false"
43
 *          stopOnSkipped="false"
44
 *          failOnWarning="false"
45
 *          failOnRisky="false"
46
 *          extensionsDirectory="tools/phpunit.d"
47
 *          printerClass="PHPUnit\TextUI\ResultPrinter"
48
 *          testSuiteLoaderClass="PHPUnit\Runner\StandardTestSuiteLoader"
49
 *          defaultTestSuite=""
50
 *          beStrictAboutChangesToGlobalState="false"
51
 *          beStrictAboutCoversAnnotation="false"
52
 *          beStrictAboutOutputDuringTests="false"
53
 *          beStrictAboutResourceUsageDuringSmallTests="false"
54
 *          beStrictAboutTestsThatDoNotTestAnything="false"
55
 *          beStrictAboutTodoAnnotatedTests="false"
56
 *          enforceTimeLimit="false"
57
 *          ignoreDeprecatedCodeUnitsFromCodeCoverage="false"
58
 *          timeoutForSmallTests="1"
59
 *          timeoutForMediumTests="10"
60
 *          timeoutForLargeTests="60"
61
 *          verbose="false"
62
 *          reverseDefectList="false"
63
 *          registerMockObjectsFromTestArgumentsRecursively="false">
64
 *   <testsuites>
65
 *     <testsuite name="My Test Suite">
66
 *       <directory suffix="Test.php" phpVersion="5.3.0" phpVersionOperator=">=">/path/to/files</directory>
67
 *       <file phpVersion="5.3.0" phpVersionOperator=">=">/path/to/MyTest.php</file>
68
 *       <exclude>/path/to/files/exclude</exclude>
69
 *     </testsuite>
70
 *   </testsuites>
71
 *
72
 *   <groups>
73
 *     <include>
74
 *       <group>name</group>
75
 *     </include>
76
 *     <exclude>
77
 *       <group>name</group>
78
 *     </exclude>
79
 *   </groups>
80
 *
81
 *   <testdoxGroups>
82
 *     <include>
83
 *       <group>name</group>
84
 *     </include>
85
 *     <exclude>
86
 *       <group>name</group>
87
 *     </exclude>
88
 *   </testdoxGroups>
89
 *
90
 *   <filter>
91
 *     <whitelist addUncoveredFilesFromWhitelist="true"
92
 *                processUncoveredFilesFromWhitelist="false">
93
 *       <directory suffix=".php">/path/to/files</directory>
94
 *       <file>/path/to/file</file>
95
 *       <exclude>
96
 *         <directory suffix=".php">/path/to/files</directory>
97
 *         <file>/path/to/file</file>
98
 *       </exclude>
99
 *     </whitelist>
100
 *   </filter>
101
 *
102
 *   <listeners>
103
 *     <listener class="MyListener" file="/optional/path/to/MyListener.php">
104
 *       <arguments>
105
 *         <array>
106
 *           <element key="0">
107
 *             <string>Sebastian</string>
108
 *           </element>
109
 *         </array>
110
 *         <integer>22</integer>
111
 *         <string>April</string>
112
 *         <double>19.78</double>
113
 *         <null/>
114
 *         <object class="stdClass"/>
115
 *         <file>MyRelativeFile.php</file>
116
 *         <directory>MyRelativeDir</directory>
117
 *       </arguments>
118
 *     </listener>
119
 *   </listeners>
120
 *
121
 *   <logging>
122
 *     <log type="coverage-html" target="/tmp/report" lowUpperBound="50" highLowerBound="90"/>
123
 *     <log type="coverage-clover" target="/tmp/clover.xml"/>
124
 *     <log type="coverage-crap4j" target="/tmp/crap.xml" threshold="30"/>
125
 *     <log type="json" target="/tmp/logfile.json"/>
126
 *     <log type="plain" target="/tmp/logfile.txt"/>
127
 *     <log type="teamcity" target="/tmp/logfile.txt"/>
128
 *     <log type="junit" target="/tmp/logfile.xml"/>
129
 *     <log type="testdox-html" target="/tmp/testdox.html"/>
130
 *     <log type="testdox-text" target="/tmp/testdox.txt"/>
131
 *     <log type="testdox-xml" target="/tmp/testdox.xml"/>
132
 *   </logging>
133
 *
134
 *   <php>
135
 *     <includePath>.</includePath>
136
 *     <ini name="foo" value="bar"/>
137
 *     <const name="foo" value="bar"/>
138
 *     <var name="foo" value="bar"/>
139
 *     <env name="foo" value="bar"/>
140
 *     <post name="foo" value="bar"/>
141
 *     <get name="foo" value="bar"/>
142
 *     <cookie name="foo" value="bar"/>
143
 *     <server name="foo" value="bar"/>
144
 *     <files name="foo" value="bar"/>
145
 *     <request name="foo" value="bar"/>
146
 *   </php>
147
 * </phpunit>
148
 * </code>
149
 */
150
class Configuration
151
{
152
    const TEST_SUITE_FILTER_SEPARATOR = ',';
153
154
    private static $instances = [];
155
156
    protected $document;
157
    protected $xpath;
158
    protected $filename;
159
160
    /**
161
     * Loads a PHPUnit configuration file.
162
     *
163
     * @param string $filename
164
     */
165
    protected function __construct($filename)
166
    {
167
        $this->filename = $filename;
168
        $this->document = Xml::loadFile($filename, false, true, true);
169
        $this->xpath    = new DOMXPath($this->document);
170
    }
171
172
    final private function __clone()
173
    {
174
    }
175
176
    /**
177
     * Returns a PHPUnit configuration object.
178
     *
179
     * @param string $filename
180
     *
181
     * @return Configuration
182
     */
183
    public static function getInstance($filename)
184
    {
185
        $realpath = \realpath($filename);
186
187
        if ($realpath === false) {
188
            throw new Exception(
189
                \sprintf(
190
                    'Could not read "%s".',
191
                    $filename
192
                )
193
            );
194
        }
195
196
        if (!isset(self::$instances[$realpath])) {
197
            self::$instances[$realpath] = new self($realpath);
198
        }
199
200
        return self::$instances[$realpath];
201
    }
202
203
    /**
204
     * Returns the realpath to the configuration file.
205
     *
206
     * @return string
207
     */
208
    public function getFilename()
209
    {
210
        return $this->filename;
211
    }
212
213
    /**
214
     * Returns the configuration for SUT filtering.
215
     *
216
     * @return array
217
     */
218
    public function getFilterConfiguration()
219
    {
220
        $addUncoveredFilesFromWhitelist     = true;
221
        $processUncoveredFilesFromWhitelist = false;
222
223
        $tmp = $this->xpath->query('filter/whitelist');
224
225
        if ($tmp->length == 0) {
226
            return [
227
                'whitelist' => []
228
            ];
229
        }
230
231
        if ($tmp->length == 1) {
232
            if ($tmp->item(0)->hasAttribute('addUncoveredFilesFromWhitelist')) {
233
                $addUncoveredFilesFromWhitelist = $this->getBoolean(
234
                    (string) $tmp->item(0)->getAttribute(
235
                        'addUncoveredFilesFromWhitelist'
236
                    ),
237
                    true
238
                );
239
            }
240
241
            if ($tmp->item(0)->hasAttribute('processUncoveredFilesFromWhitelist')) {
242
                $processUncoveredFilesFromWhitelist = $this->getBoolean(
243
                    (string) $tmp->item(0)->getAttribute(
244
                        'processUncoveredFilesFromWhitelist'
245
                    ),
246
                    false
247
                );
248
            }
249
        }
250
251
        return [
252
            'whitelist' => [
253
                'addUncoveredFilesFromWhitelist'     => $addUncoveredFilesFromWhitelist,
254
                'processUncoveredFilesFromWhitelist' => $processUncoveredFilesFromWhitelist,
255
                'include'                            => [
256
                    'directory' => $this->readFilterDirectories(
257
                        'filter/whitelist/directory'
258
                    ),
259
                    'file' => $this->readFilterFiles(
260
                        'filter/whitelist/file'
261
                    )
262
                ],
263
                'exclude' => [
264
                    'directory' => $this->readFilterDirectories(
265
                        'filter/whitelist/exclude/directory'
266
                    ),
267
                    'file' => $this->readFilterFiles(
268
                        'filter/whitelist/exclude/file'
269
                    )
270
                ]
271
            ]
272
        ];
273
    }
274
275
    /**
276
     * Returns the configuration for groups.
277
     *
278
     * @return array
279
     */
280
    public function getGroupConfiguration()
281
    {
282
        return $this->parseGroupConfiguration('groups');
283
    }
284
285
    /**
286
     * Returns the configuration for testdox groups.
287
     *
288
     * @return array
289
     */
290
    public function getTestdoxGroupConfiguration()
291
    {
292
        return $this->parseGroupConfiguration('testdoxGroups');
293
    }
294
295
    /**
296
     * @param string $root
297
     *
298
     * @return array
299
     */
300
    private function parseGroupConfiguration($root)
301
    {
302
        $groups = [
303
            'include' => [],
304
            'exclude' => []
305
        ];
306
307
        foreach ($this->xpath->query($root . '/include/group') as $group) {
308
            $groups['include'][] = (string) $group->textContent;
309
        }
310
311
        foreach ($this->xpath->query($root . '/exclude/group') as $group) {
312
            $groups['exclude'][] = (string) $group->textContent;
313
        }
314
315
        return $groups;
316
    }
317
318
    /**
319
     * Returns the configuration for listeners.
320
     *
321
     * @return array
322
     */
323
    public function getListenerConfiguration()
324
    {
325
        $result = [];
326
327
        foreach ($this->xpath->query('listeners/listener') as $listener) {
328
            $class     = (string) $listener->getAttribute('class');
329
            $file      = '';
330
            $arguments = [];
331
332
            if ($listener->getAttribute('file')) {
333
                $file = $this->toAbsolutePath(
334
                    (string) $listener->getAttribute('file'),
335
                    true
336
                );
337
            }
338
339
            foreach ($listener->childNodes as $node) {
340
                if ($node instanceof DOMElement && $node->tagName == 'arguments') {
341
                    foreach ($node->childNodes as $argument) {
342
                        if ($argument instanceof DOMElement) {
343
                            if ($argument->tagName == 'file' || $argument->tagName == 'directory') {
344
                                $arguments[] = $this->toAbsolutePath((string) $argument->textContent);
345
                            } else {
346
                                $arguments[] = Xml::xmlToVariable($argument);
347
                            }
348
                        }
349
                    }
350
                }
351
            }
352
353
            $result[] = [
354
                'class'     => $class,
355
                'file'      => $file,
356
                'arguments' => $arguments
357
            ];
358
        }
359
360
        return $result;
361
    }
362
363
    /**
364
     * Returns the logging configuration.
365
     *
366
     * @return array
367
     */
368
    public function getLoggingConfiguration()
369
    {
370
        $result = [];
371
372
        foreach ($this->xpath->query('logging/log') as $log) {
373
            $type   = (string) $log->getAttribute('type');
374
            $target = (string) $log->getAttribute('target');
375
376
            if (!$target) {
377
                continue;
378
            }
379
380
            $target = $this->toAbsolutePath($target);
381
382
            if ($type == 'coverage-html') {
383
                if ($log->hasAttribute('lowUpperBound')) {
384
                    $result['lowUpperBound'] = $this->getInteger(
385
                        (string) $log->getAttribute('lowUpperBound'),
386
                        50
387
                    );
388
                }
389
390
                if ($log->hasAttribute('highLowerBound')) {
391
                    $result['highLowerBound'] = $this->getInteger(
392
                        (string) $log->getAttribute('highLowerBound'),
393
                        90
394
                    );
395
                }
396
            } elseif ($type == 'coverage-crap4j') {
397
                if ($log->hasAttribute('threshold')) {
398
                    $result['crap4jThreshold'] = $this->getInteger(
399
                        (string) $log->getAttribute('threshold'),
400
                        30
401
                    );
402
                }
403
            } elseif ($type == 'coverage-text') {
404
                if ($log->hasAttribute('showUncoveredFiles')) {
405
                    $result['coverageTextShowUncoveredFiles'] = $this->getBoolean(
406
                        (string) $log->getAttribute('showUncoveredFiles'),
407
                        false
408
                    );
409
                }
410
                if ($log->hasAttribute('showOnlySummary')) {
411
                    $result['coverageTextShowOnlySummary'] = $this->getBoolean(
412
                        (string) $log->getAttribute('showOnlySummary'),
413
                        false
414
                    );
415
                }
416
            }
417
418
            $result[$type] = $target;
419
        }
420
421
        return $result;
422
    }
423
424
    /**
425
     * Returns the PHP configuration.
426
     *
427
     * @return array
428
     */
429
    public function getPHPConfiguration()
430
    {
431
        $result = [
432
            'include_path' => [],
433
            'ini'          => [],
434
            'const'        => [],
435
            'var'          => [],
436
            'env'          => [],
437
            'post'         => [],
438
            'get'          => [],
439
            'cookie'       => [],
440
            'server'       => [],
441
            'files'        => [],
442
            'request'      => []
443
        ];
444
445
        foreach ($this->xpath->query('php/includePath') as $includePath) {
446
            $path = (string) $includePath->textContent;
447
448
            if ($path) {
449
                $result['include_path'][] = $this->toAbsolutePath($path);
450
            }
451
        }
452
453
        foreach ($this->xpath->query('php/ini') as $ini) {
454
            $name  = (string) $ini->getAttribute('name');
455
            $value = (string) $ini->getAttribute('value');
456
457
            $result['ini'][$name] = $value;
458
        }
459
460
        foreach ($this->xpath->query('php/const') as $const) {
461
            $name  = (string) $const->getAttribute('name');
462
            $value = (string) $const->getAttribute('value');
463
464
            $result['const'][$name] = $this->getBoolean($value, $value);
465
        }
466
467
        foreach (['var', 'env', 'post', 'get', 'cookie', 'server', 'files', 'request'] as $array) {
468
            foreach ($this->xpath->query('php/' . $array) as $var) {
469
                $name     = (string) $var->getAttribute('name');
470
                $value    = (string) $var->getAttribute('value');
471
                $verbatim = false;
472
473
                if ($var->hasAttribute('verbatim')) {
474
                    $verbatim = $this->getBoolean($var->getAttribute('verbatim'), false);
475
                }
476
477
                if (!$verbatim) {
478
                    $value = $this->getBoolean($value, $value);
479
                }
480
481
                $result[$array][$name] = $value;
482
            }
483
        }
484
485
        return $result;
486
    }
487
488
    /**
489
     * Handles the PHP configuration.
490
     */
491
    public function handlePHPConfiguration()
492
    {
493
        $configuration = $this->getPHPConfiguration();
494
495
        if (!empty($configuration['include_path'])) {
496
            \ini_set(
497
                'include_path',
498
                \implode(PATH_SEPARATOR, $configuration['include_path']) .
499
                PATH_SEPARATOR .
500
                \ini_get('include_path')
501
            );
502
        }
503
504
        foreach ($configuration['ini'] as $name => $value) {
505
            if (\defined($value)) {
506
                $value = \constant($value);
507
            }
508
509
            \ini_set($name, $value);
510
        }
511
512
        foreach ($configuration['const'] as $name => $value) {
513
            if (!\defined($name)) {
514
                \define($name, $value);
515
            }
516
        }
517
518
        foreach (['var', 'post', 'get', 'cookie', 'server', 'files', 'request'] as $array) {
519
            // See https://github.com/sebastianbergmann/phpunit/issues/277
520
            switch ($array) {
521
                case 'var':
522
                    $target = &$GLOBALS;
523
                    break;
524
525
                case 'server':
526
                    $target = &$_SERVER;
527
                    break;
528
529
                default:
530
                    $target = &$GLOBALS['_' . \strtoupper($array)];
531
                    break;
532
            }
533
534
            foreach ($configuration[$array] as $name => $value) {
535
                $target[$name] = $value;
536
            }
537
        }
538
539
        foreach ($configuration['env'] as $name => $value) {
540
            if (false === \getenv($name)) {
541
                \putenv("{$name}={$value}");
542
            }
543
            if (!isset($_ENV[$name])) {
544
                $_ENV[$name] = $value;
545
            }
546
        }
547
    }
548
549
    /**
550
     * Returns the PHPUnit configuration.
551
     *
552
     * @return array
553
     */
554
    public function getPHPUnitConfiguration()
555
    {
556
        $result = [];
557
        $root   = $this->document->documentElement;
558
559
        if ($root->hasAttribute('cacheTokens')) {
560
            $result['cacheTokens'] = $this->getBoolean(
561
                (string) $root->getAttribute('cacheTokens'),
562
                false
563
            );
564
        }
565
566
        if ($root->hasAttribute('columns')) {
567
            $columns = (string) $root->getAttribute('columns');
568
569
            if ($columns == 'max') {
570
                $result['columns'] = 'max';
571
            } else {
572
                $result['columns'] = $this->getInteger($columns, 80);
573
            }
574
        }
575
576
        if ($root->hasAttribute('colors')) {
577
            /* only allow boolean for compatibility with previous versions
578
              'always' only allowed from command line */
579
            if ($this->getBoolean($root->getAttribute('colors'), false)) {
580
                $result['colors'] = ResultPrinter::COLOR_AUTO;
581
            } else {
582
                $result['colors'] = ResultPrinter::COLOR_NEVER;
583
            }
584
        }
585
586
        /*
587
         * Issue #657
588
         */
589
        if ($root->hasAttribute('stderr')) {
590
            $result['stderr'] = $this->getBoolean(
591
                (string) $root->getAttribute('stderr'),
592
                false
593
            );
594
        }
595
596
        if ($root->hasAttribute('backupGlobals')) {
597
            $result['backupGlobals'] = $this->getBoolean(
598
                (string) $root->getAttribute('backupGlobals'),
599
                false
600
            );
601
        }
602
603
        if ($root->hasAttribute('backupStaticAttributes')) {
604
            $result['backupStaticAttributes'] = $this->getBoolean(
605
                (string) $root->getAttribute('backupStaticAttributes'),
606
                false
607
            );
608
        }
609
610
        if ($root->getAttribute('bootstrap')) {
611
            $result['bootstrap'] = $this->toAbsolutePath(
612
                (string) $root->getAttribute('bootstrap')
613
            );
614
        }
615
616
        if ($root->hasAttribute('convertErrorsToExceptions')) {
617
            $result['convertErrorsToExceptions'] = $this->getBoolean(
618
                (string) $root->getAttribute('convertErrorsToExceptions'),
619
                true
620
            );
621
        }
622
623
        if ($root->hasAttribute('convertNoticesToExceptions')) {
624
            $result['convertNoticesToExceptions'] = $this->getBoolean(
625
                (string) $root->getAttribute('convertNoticesToExceptions'),
626
                true
627
            );
628
        }
629
630
        if ($root->hasAttribute('convertWarningsToExceptions')) {
631
            $result['convertWarningsToExceptions'] = $this->getBoolean(
632
                (string) $root->getAttribute('convertWarningsToExceptions'),
633
                true
634
            );
635
        }
636
637
        if ($root->hasAttribute('forceCoversAnnotation')) {
638
            $result['forceCoversAnnotation'] = $this->getBoolean(
639
                (string) $root->getAttribute('forceCoversAnnotation'),
640
                false
641
            );
642
        }
643
644
        if ($root->hasAttribute('disableCodeCoverageIgnore')) {
645
            $result['disableCodeCoverageIgnore'] = $this->getBoolean(
646
                (string) $root->getAttribute('disableCodeCoverageIgnore'),
647
                false
648
            );
649
        }
650
651
        if ($root->hasAttribute('processIsolation')) {
652
            $result['processIsolation'] = $this->getBoolean(
653
                (string) $root->getAttribute('processIsolation'),
654
                false
655
            );
656
        }
657
658
        if ($root->hasAttribute('stopOnError')) {
659
            $result['stopOnError'] = $this->getBoolean(
660
                (string) $root->getAttribute('stopOnError'),
661
                false
662
            );
663
        }
664
665
        if ($root->hasAttribute('stopOnFailure')) {
666
            $result['stopOnFailure'] = $this->getBoolean(
667
                (string) $root->getAttribute('stopOnFailure'),
668
                false
669
            );
670
        }
671
672
        if ($root->hasAttribute('stopOnWarning')) {
673
            $result['stopOnWarning'] = $this->getBoolean(
674
                (string) $root->getAttribute('stopOnWarning'),
675
                false
676
            );
677
        }
678
679
        if ($root->hasAttribute('stopOnIncomplete')) {
680
            $result['stopOnIncomplete'] = $this->getBoolean(
681
                (string) $root->getAttribute('stopOnIncomplete'),
682
                false
683
            );
684
        }
685
686
        if ($root->hasAttribute('stopOnRisky')) {
687
            $result['stopOnRisky'] = $this->getBoolean(
688
                (string) $root->getAttribute('stopOnRisky'),
689
                false
690
            );
691
        }
692
693
        if ($root->hasAttribute('stopOnSkipped')) {
694
            $result['stopOnSkipped'] = $this->getBoolean(
695
                (string) $root->getAttribute('stopOnSkipped'),
696
                false
697
            );
698
        }
699
700
        if ($root->hasAttribute('failOnWarning')) {
701
            $result['failOnWarning'] = $this->getBoolean(
702
                (string) $root->getAttribute('failOnWarning'),
703
                false
704
            );
705
        }
706
707
        if ($root->hasAttribute('failOnRisky')) {
708
            $result['failOnRisky'] = $this->getBoolean(
709
                (string) $root->getAttribute('failOnRisky'),
710
                false
711
            );
712
        }
713
714
        if ($root->hasAttribute('testSuiteLoaderClass')) {
715
            $result['testSuiteLoaderClass'] = (string) $root->getAttribute(
716
                'testSuiteLoaderClass'
717
            );
718
        }
719
720
        if ($root->hasAttribute('defaultTestSuite')) {
721
            $result['defaultTestSuite'] = (string) $root->getAttribute(
722
                'defaultTestSuite'
723
            );
724
        }
725
726
        if ($root->getAttribute('testSuiteLoaderFile')) {
727
            $result['testSuiteLoaderFile'] = $this->toAbsolutePath(
728
                (string) $root->getAttribute('testSuiteLoaderFile')
729
            );
730
        }
731
732
        if ($root->hasAttribute('printerClass')) {
733
            $result['printerClass'] = (string) $root->getAttribute(
734
                'printerClass'
735
            );
736
        }
737
738
        if ($root->getAttribute('printerFile')) {
739
            $result['printerFile'] = $this->toAbsolutePath(
740
                (string) $root->getAttribute('printerFile')
741
            );
742
        }
743
744
        if ($root->hasAttribute('beStrictAboutChangesToGlobalState')) {
745
            $result['beStrictAboutChangesToGlobalState'] = $this->getBoolean(
746
                (string) $root->getAttribute('beStrictAboutChangesToGlobalState'),
747
                false
748
            );
749
        }
750
751
        if ($root->hasAttribute('beStrictAboutOutputDuringTests')) {
752
            $result['disallowTestOutput'] = $this->getBoolean(
753
                (string) $root->getAttribute('beStrictAboutOutputDuringTests'),
754
                false
755
            );
756
        }
757
758
        if ($root->hasAttribute('beStrictAboutResourceUsageDuringSmallTests')) {
759
            $result['beStrictAboutResourceUsageDuringSmallTests'] = $this->getBoolean(
760
                (string) $root->getAttribute('beStrictAboutResourceUsageDuringSmallTests'),
761
                false
762
            );
763
        }
764
765
        if ($root->hasAttribute('beStrictAboutTestsThatDoNotTestAnything')) {
766
            $result['reportUselessTests'] = $this->getBoolean(
767
                (string) $root->getAttribute('beStrictAboutTestsThatDoNotTestAnything'),
768
                true
769
            );
770
        }
771
772
        if ($root->hasAttribute('beStrictAboutTodoAnnotatedTests')) {
773
            $result['disallowTodoAnnotatedTests'] = $this->getBoolean(
774
                (string) $root->getAttribute('beStrictAboutTodoAnnotatedTests'),
775
                false
776
            );
777
        }
778
779
        if ($root->hasAttribute('beStrictAboutCoversAnnotation')) {
780
            $result['strictCoverage'] = $this->getBoolean(
781
                (string) $root->getAttribute('beStrictAboutCoversAnnotation'),
782
                false
783
            );
784
        }
785
786
        if ($root->hasAttribute('enforceTimeLimit')) {
787
            $result['enforceTimeLimit'] = $this->getBoolean(
788
                (string) $root->getAttribute('enforceTimeLimit'),
789
                false
790
            );
791
        }
792
793
        if ($root->hasAttribute('ignoreDeprecatedCodeUnitsFromCodeCoverage')) {
794
            $result['ignoreDeprecatedCodeUnitsFromCodeCoverage'] = $this->getBoolean(
795
                (string) $root->getAttribute('ignoreDeprecatedCodeUnitsFromCodeCoverage'),
796
                false
797
            );
798
        }
799
800
        if ($root->hasAttribute('timeoutForSmallTests')) {
801
            $result['timeoutForSmallTests'] = $this->getInteger(
802
                (string) $root->getAttribute('timeoutForSmallTests'),
803
                1
804
            );
805
        }
806
807
        if ($root->hasAttribute('timeoutForMediumTests')) {
808
            $result['timeoutForMediumTests'] = $this->getInteger(
809
                (string) $root->getAttribute('timeoutForMediumTests'),
810
                10
811
            );
812
        }
813
814
        if ($root->hasAttribute('timeoutForLargeTests')) {
815
            $result['timeoutForLargeTests'] = $this->getInteger(
816
                (string) $root->getAttribute('timeoutForLargeTests'),
817
                60
818
            );
819
        }
820
821
        if ($root->hasAttribute('reverseDefectList')) {
822
            $result['reverseDefectList'] = $this->getBoolean(
823
                (string) $root->getAttribute('reverseDefectList'),
824
                false
825
            );
826
        }
827
828
        if ($root->hasAttribute('verbose')) {
829
            $result['verbose'] = $this->getBoolean(
830
                (string) $root->getAttribute('verbose'),
831
                false
832
            );
833
        }
834
835
        if ($root->hasAttribute('registerMockObjectsFromTestArgumentsRecursively')) {
836
            $result['registerMockObjectsFromTestArgumentsRecursively'] = $this->getBoolean(
837
                (string) $root->getAttribute('registerMockObjectsFromTestArgumentsRecursively'),
838
                false
839
            );
840
        }
841
842
        if ($root->hasAttribute('extensionsDirectory')) {
843
            $result['extensionsDirectory'] = $this->toAbsolutePath(
844
                (string) $root->getAttribute(
845
                    'extensionsDirectory'
846
                )
847
            );
848
        }
849
850
        return $result;
851
    }
852
853
    /**
854
     * Returns the test suite configuration.
855
     *
856
     * @return TestSuite
857
     */
858
    public function getTestSuiteConfiguration($testSuiteFilter = null)
859
    {
860
        $testSuiteNodes = $this->xpath->query('testsuites/testsuite');
861
862
        if ($testSuiteNodes->length == 0) {
863
            $testSuiteNodes = $this->xpath->query('testsuite');
864
        }
865
866
        if ($testSuiteNodes->length == 1) {
867
            return $this->getTestSuite($testSuiteNodes->item(0), $testSuiteFilter);
868
        }
869
870
        if ($testSuiteNodes->length > 1) {
871
            $suite = new TestSuite;
872
873
            foreach ($testSuiteNodes as $testSuiteNode) {
874
                $suite->addTestSuite(
875
                    $this->getTestSuite($testSuiteNode, $testSuiteFilter)
876
                );
877
            }
878
879
            return $suite;
880
        }
881
    }
882
883
    /**
884
     * Returns the test suite names from the configuration.
885
     *
886
     * @return array
887
     */
888
    public function getTestSuiteNames()
889
    {
890
        $names = [];
891
        $nodes = $this->xpath->query('*/testsuite');
892
        foreach ($nodes as $node) {
893
            $names[] = $node->getAttribute('name');
894
        }
895
896
        return $names;
897
    }
898
899
    /**
900
     * @param DOMElement $testSuiteNode
901
     *
902
     * @return TestSuite
903
     */
904
    protected function getTestSuite(DOMElement $testSuiteNode, $testSuiteFilter = null)
905
    {
906
        if ($testSuiteNode->hasAttribute('name')) {
907
            $suite = new TestSuite(
908
                (string) $testSuiteNode->getAttribute('name')
909
            );
910
        } else {
911
            $suite = new TestSuite;
912
        }
913
914
        $exclude = [];
915
916
        foreach ($testSuiteNode->getElementsByTagName('exclude') as $excludeNode) {
917
            $excludeFile = (string) $excludeNode->textContent;
918
            if ($excludeFile) {
919
                $exclude[] = $this->toAbsolutePath($excludeFile);
920
            }
921
        }
922
923
        $fileIteratorFacade = new File_Iterator_Facade;
924
        $testSuiteFilter    = $testSuiteFilter ? \explode(self::TEST_SUITE_FILTER_SEPARATOR, $testSuiteFilter) : [];
925
926
        foreach ($testSuiteNode->getElementsByTagName('directory') as $directoryNode) {
927
            if (!empty($testSuiteFilter) && !\in_array($directoryNode->parentNode->getAttribute('name'), $testSuiteFilter)) {
928
                continue;
929
            }
930
931
            $directory = (string) $directoryNode->textContent;
932
933
            if (empty($directory)) {
934
                continue;
935
            }
936
937
            if ($directoryNode->hasAttribute('phpVersion')) {
938
                $phpVersion = (string) $directoryNode->getAttribute('phpVersion');
939
            } else {
940
                $phpVersion = PHP_VERSION;
941
            }
942
943
            if ($directoryNode->hasAttribute('phpVersionOperator')) {
944
                $phpVersionOperator = (string) $directoryNode->getAttribute('phpVersionOperator');
945
            } else {
946
                $phpVersionOperator = '>=';
947
            }
948
949
            if (!\version_compare(PHP_VERSION, $phpVersion, $phpVersionOperator)) {
950
                continue;
951
            }
952
953
            if ($directoryNode->hasAttribute('prefix')) {
954
                $prefix = (string) $directoryNode->getAttribute('prefix');
955
            } else {
956
                $prefix = '';
957
            }
958
959
            if ($directoryNode->hasAttribute('suffix')) {
960
                $suffix = (string) $directoryNode->getAttribute('suffix');
961
            } else {
962
                $suffix = 'Test.php';
963
            }
964
965
            $files = $fileIteratorFacade->getFilesAsArray(
966
                $this->toAbsolutePath($directory),
967
                $suffix,
968
                $prefix,
969
                $exclude
970
            );
971
            $suite->addTestFiles($files);
972
        }
973
974
        foreach ($testSuiteNode->getElementsByTagName('file') as $fileNode) {
975
            if (!empty($testSuiteFilter) && !\in_array($fileNode->parentNode->getAttribute('name'), $testSuiteFilter)) {
976
                continue;
977
            }
978
979
            $file = (string) $fileNode->textContent;
980
981
            if (empty($file)) {
982
                continue;
983
            }
984
985
            // Get the absolute path to the file
986
            $file = $fileIteratorFacade->getFilesAsArray(
987
                $this->toAbsolutePath($file)
988
            );
989
990
            if (!isset($file[0])) {
991
                continue;
992
            }
993
994
            $file = $file[0];
995
996
            if ($fileNode->hasAttribute('phpVersion')) {
997
                $phpVersion = (string) $fileNode->getAttribute('phpVersion');
998
            } else {
999
                $phpVersion = PHP_VERSION;
1000
            }
1001
1002
            if ($fileNode->hasAttribute('phpVersionOperator')) {
1003
                $phpVersionOperator = (string) $fileNode->getAttribute('phpVersionOperator');
1004
            } else {
1005
                $phpVersionOperator = '>=';
1006
            }
1007
1008
            if (!\version_compare(PHP_VERSION, $phpVersion, $phpVersionOperator)) {
1009
                continue;
1010
            }
1011
1012
            $suite->addTestFile($file);
1013
        }
1014
1015
        return $suite;
1016
    }
1017
1018
    /**
1019
     * @param string $value
1020
     * @param bool   $default
1021
     *
1022
     * @return bool
1023
     */
1024
    protected function getBoolean($value, $default)
1025
    {
1026
        if (\strtolower($value) == 'false') {
1027
            return false;
1028
        }
1029
1030
        if (\strtolower($value) == 'true') {
1031
            return true;
1032
        }
1033
1034
        return $default;
1035
    }
1036
1037
    /**
1038
     * @param string $value
1039
     * @param bool   $default
1040
     *
1041
     * @return bool
1042
     */
1043
    protected function getInteger($value, $default)
1044
    {
1045
        if (\is_numeric($value)) {
1046
            return (int) $value;
1047
        }
1048
1049
        return $default;
1050
    }
1051
1052
    /**
1053
     * @param string $query
1054
     *
1055
     * @return array
1056
     */
1057
    protected function readFilterDirectories($query)
1058
    {
1059
        $directories = [];
1060
1061
        foreach ($this->xpath->query($query) as $directory) {
1062
            $directoryPath = (string) $directory->textContent;
1063
1064
            if (!$directoryPath) {
1065
                continue;
1066
            }
1067
1068
            if ($directory->hasAttribute('prefix')) {
1069
                $prefix = (string) $directory->getAttribute('prefix');
1070
            } else {
1071
                $prefix = '';
1072
            }
1073
1074
            if ($directory->hasAttribute('suffix')) {
1075
                $suffix = (string) $directory->getAttribute('suffix');
1076
            } else {
1077
                $suffix = '.php';
1078
            }
1079
1080
            if ($directory->hasAttribute('group')) {
1081
                $group = (string) $directory->getAttribute('group');
1082
            } else {
1083
                $group = 'DEFAULT';
1084
            }
1085
1086
            $directories[] = [
1087
                'path'   => $this->toAbsolutePath($directoryPath),
1088
                'prefix' => $prefix,
1089
                'suffix' => $suffix,
1090
                'group'  => $group
1091
            ];
1092
        }
1093
1094
        return $directories;
1095
    }
1096
1097
    /**
1098
     * @param string $query
1099
     *
1100
     * @return array
1101
     */
1102
    protected function readFilterFiles($query)
1103
    {
1104
        $files = [];
1105
1106
        foreach ($this->xpath->query($query) as $file) {
1107
            $filePath = (string) $file->textContent;
1108
1109
            if ($filePath) {
1110
                $files[] = $this->toAbsolutePath($filePath);
1111
            }
1112
        }
1113
1114
        return $files;
1115
    }
1116
1117
    /**
1118
     * @param string $path
1119
     * @param bool   $useIncludePath
1120
     *
1121
     * @return string
1122
     */
1123
    protected function toAbsolutePath($path, $useIncludePath = false)
1124
    {
1125
        $path = \trim($path);
1126
1127
        if ($path[0] === '/') {
1128
            return $path;
1129
        }
1130
1131
        // Matches the following on Windows:
1132
        //  - \\NetworkComputer\Path
1133
        //  - \\.\D:
1134
        //  - \\.\c:
1135
        //  - C:\Windows
1136
        //  - C:\windows
1137
        //  - C:/windows
1138
        //  - c:/windows
1139
        if (\defined('PHP_WINDOWS_VERSION_BUILD') &&
1140
            ($path[0] === '\\' || (\strlen($path) >= 3 && \preg_match('#^[A-Z]\:[/\\\]#i', \substr($path, 0, 3))))) {
1141
            return $path;
1142
        }
1143
1144
        // Stream
1145
        if (\strpos($path, '://') !== false) {
1146
            return $path;
1147
        }
1148
1149
        $file = \dirname($this->filename) . DIRECTORY_SEPARATOR . $path;
1150
1151
        if ($useIncludePath && !\file_exists($file)) {
1152
            $includePathFile = \stream_resolve_include_path($path);
1153
1154
            if ($includePathFile) {
1155
                $file = $includePathFile;
1156
            }
1157
        }
1158
1159
        return $file;
1160
    }
1161
}
1162