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