PageRenderTime 73ms CodeModel.GetById 18ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/phpunit/phpunit/src/TextUI/Command.php

https://bitbucket.org/alan_cordova/api-sb-map
PHP | 1172 lines | 870 code | 188 blank | 114 comment | 97 complexity | 806fdf8d70183514c1c8039997b47017 MD5 | raw file
   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 * A TestRunner for the Command Line Interface (CLI)
  13 * PHP SAPI Module.
  14 */
  15class PHPUnit_TextUI_Command
  16{
  17    /**
  18     * @var array
  19     */
  20    protected $arguments = [
  21        'listGroups'              => false,
  22        'listSuites'              => false,
  23        'loader'                  => null,
  24        'useDefaultConfiguration' => true,
  25        'loadedExtensions'        => [],
  26        'notLoadedExtensions'     => []
  27    ];
  28
  29    /**
  30     * @var array
  31     */
  32    protected $options = [];
  33
  34    /**
  35     * @var array
  36     */
  37    protected $longOptions = [
  38        'atleast-version='        => null,
  39        'bootstrap='              => null,
  40        'colors=='                => null,
  41        'columns='                => null,
  42        'configuration='          => null,
  43        'coverage-clover='        => null,
  44        'coverage-crap4j='        => null,
  45        'coverage-html='          => null,
  46        'coverage-php='           => null,
  47        'coverage-text=='         => null,
  48        'coverage-xml='           => null,
  49        'debug'                   => null,
  50        'disallow-test-output'    => null,
  51        'disallow-resource-usage' => null,
  52        'disallow-todo-tests'     => null,
  53        'enforce-time-limit'      => null,
  54        'exclude-group='          => null,
  55        'filter='                 => null,
  56        'generate-configuration'  => null,
  57        'group='                  => null,
  58        'help'                    => null,
  59        'include-path='           => null,
  60        'list-groups'             => null,
  61        'list-suites'             => null,
  62        'loader='                 => null,
  63        'log-json='               => null,
  64        'log-junit='              => null,
  65        'log-tap='                => null,
  66        'log-teamcity='           => null,
  67        'no-configuration'        => null,
  68        'no-coverage'             => null,
  69        'no-extensions'           => null,
  70        'no-globals-backup'       => null,
  71        'printer='                => null,
  72        'process-isolation'       => null,
  73        'repeat='                 => null,
  74        'report-useless-tests'    => null,
  75        'reverse-list'            => null,
  76        'static-backup'           => null,
  77        'stderr'                  => null,
  78        'stop-on-error'           => null,
  79        'stop-on-failure'         => null,
  80        'stop-on-warning'         => null,
  81        'stop-on-incomplete'      => null,
  82        'stop-on-risky'           => null,
  83        'stop-on-skipped'         => null,
  84        'fail-on-warning'         => null,
  85        'fail-on-risky'           => null,
  86        'strict-coverage'         => null,
  87        'disable-coverage-ignore' => null,
  88        'strict-global-state'     => null,
  89        'tap'                     => null,
  90        'teamcity'                => null,
  91        'testdox'                 => null,
  92        'testdox-group='          => null,
  93        'testdox-exclude-group='  => null,
  94        'testdox-html='           => null,
  95        'testdox-text='           => null,
  96        'testdox-xml='            => null,
  97        'test-suffix='            => null,
  98        'testsuite='              => null,
  99        'verbose'                 => null,
 100        'version'                 => null,
 101        'whitelist='              => null
 102    ];
 103
 104    /**
 105     * @var bool
 106     */
 107    private $versionStringPrinted = false;
 108
 109    /**
 110     * @param bool $exit
 111     */
 112    public static function main($exit = true)
 113    {
 114        $command = new static;
 115
 116        return $command->run($_SERVER['argv'], $exit);
 117    }
 118
 119    /**
 120     * @param array $argv
 121     * @param bool  $exit
 122     *
 123     * @return int
 124     */
 125    public function run(array $argv, $exit = true)
 126    {
 127        $this->handleArguments($argv);
 128
 129        $runner = $this->createRunner();
 130
 131        if (is_object($this->arguments['test']) &&
 132            $this->arguments['test'] instanceof PHPUnit_Framework_Test) {
 133            $suite = $this->arguments['test'];
 134        } else {
 135            $suite = $runner->getTest(
 136                $this->arguments['test'],
 137                $this->arguments['testFile'],
 138                $this->arguments['testSuffixes']
 139            );
 140        }
 141
 142        if ($this->arguments['listGroups']) {
 143            $this->printVersionString();
 144
 145            print "Available test group(s):\n";
 146
 147            $groups = $suite->getGroups();
 148            sort($groups);
 149
 150            foreach ($groups as $group) {
 151                print " - $group\n";
 152            }
 153
 154            if ($exit) {
 155                exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
 156            } else {
 157                return PHPUnit_TextUI_TestRunner::SUCCESS_EXIT;
 158            }
 159        }
 160
 161        if ($this->arguments['listSuites']) {
 162            $this->printVersionString();
 163
 164            print "Available test suite(s):\n";
 165
 166            $configuration = PHPUnit_Util_Configuration::getInstance(
 167                $this->arguments['configuration']
 168            );
 169
 170            $suiteNames = $configuration->getTestSuiteNames();
 171            foreach ($suiteNames as $suiteName) {
 172                print " - $suiteName\n";
 173            }
 174
 175            if ($exit) {
 176                exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
 177            } else {
 178                return PHPUnit_TextUI_TestRunner::SUCCESS_EXIT;
 179            }
 180        }
 181
 182        unset($this->arguments['test']);
 183        unset($this->arguments['testFile']);
 184
 185        try {
 186            $result = $runner->doRun($suite, $this->arguments, $exit);
 187        } catch (PHPUnit_Framework_Exception $e) {
 188            print $e->getMessage() . "\n";
 189        }
 190
 191        $return = PHPUnit_TextUI_TestRunner::FAILURE_EXIT;
 192
 193        if (isset($result) && $result->wasSuccessful(false)) {
 194            $return = PHPUnit_TextUI_TestRunner::SUCCESS_EXIT;
 195        } elseif (!isset($result) || $result->errorCount() > 0) {
 196            $return = PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT;
 197        }
 198
 199        if ($exit) {
 200            exit($return);
 201        }
 202
 203        return $return;
 204    }
 205
 206    /**
 207     * Create a TestRunner, override in subclasses.
 208     *
 209     * @return PHPUnit_TextUI_TestRunner
 210     */
 211    protected function createRunner()
 212    {
 213        return new PHPUnit_TextUI_TestRunner($this->arguments['loader']);
 214    }
 215
 216    /**
 217     * Handles the command-line arguments.
 218     *
 219     * A child class of PHPUnit_TextUI_Command can hook into the argument
 220     * parsing by adding the switch(es) to the $longOptions array and point to a
 221     * callback method that handles the switch(es) in the child class like this
 222     *
 223     * <code>
 224     * <?php
 225     * class MyCommand extends PHPUnit_TextUI_Command
 226     * {
 227     *     public function __construct()
 228     *     {
 229     *         // my-switch won't accept a value, it's an on/off
 230     *         $this->longOptions['my-switch'] = 'myHandler';
 231     *         // my-secondswitch will accept a value - note the equals sign
 232     *         $this->longOptions['my-secondswitch='] = 'myOtherHandler';
 233     *     }
 234     *
 235     *     // --my-switch  -> myHandler()
 236     *     protected function myHandler()
 237     *     {
 238     *     }
 239     *
 240     *     // --my-secondswitch foo -> myOtherHandler('foo')
 241     *     protected function myOtherHandler ($value)
 242     *     {
 243     *     }
 244     *
 245     *     // You will also need this - the static keyword in the
 246     *     // PHPUnit_TextUI_Command will mean that it'll be
 247     *     // PHPUnit_TextUI_Command that gets instantiated,
 248     *     // not MyCommand
 249     *     public static function main($exit = true)
 250     *     {
 251     *         $command = new static;
 252     *
 253     *         return $command->run($_SERVER['argv'], $exit);
 254     *     }
 255     *
 256     * }
 257     * </code>
 258     *
 259     * @param array $argv
 260     */
 261    protected function handleArguments(array $argv)
 262    {
 263        if (defined('__PHPUNIT_PHAR__')) {
 264            $this->longOptions['check-version'] = null;
 265            $this->longOptions['selfupdate']    = null;
 266            $this->longOptions['self-update']   = null;
 267            $this->longOptions['selfupgrade']   = null;
 268            $this->longOptions['self-upgrade']  = null;
 269        }
 270
 271        try {
 272            $this->options = PHPUnit_Util_Getopt::getopt(
 273                $argv,
 274                'd:c:hv',
 275                array_keys($this->longOptions)
 276            );
 277        } catch (PHPUnit_Framework_Exception $e) {
 278            $this->showError($e->getMessage());
 279        }
 280
 281        foreach ($this->options[0] as $option) {
 282            switch ($option[0]) {
 283                case '--colors':
 284                    $this->arguments['colors'] = $option[1] ?: PHPUnit_TextUI_ResultPrinter::COLOR_AUTO;
 285                    break;
 286
 287                case '--bootstrap':
 288                    $this->arguments['bootstrap'] = $option[1];
 289                    break;
 290
 291                case '--columns':
 292                    if (is_numeric($option[1])) {
 293                        $this->arguments['columns'] = (int) $option[1];
 294                    } elseif ($option[1] == 'max') {
 295                        $this->arguments['columns'] = 'max';
 296                    }
 297                    break;
 298
 299                case 'c':
 300                case '--configuration':
 301                    $this->arguments['configuration'] = $option[1];
 302                    break;
 303
 304                case '--coverage-clover':
 305                    $this->arguments['coverageClover'] = $option[1];
 306                    break;
 307
 308                case '--coverage-crap4j':
 309                    $this->arguments['coverageCrap4J'] = $option[1];
 310                    break;
 311
 312                case '--coverage-html':
 313                    $this->arguments['coverageHtml'] = $option[1];
 314                    break;
 315
 316                case '--coverage-php':
 317                    $this->arguments['coveragePHP'] = $option[1];
 318                    break;
 319
 320                case '--coverage-text':
 321                    if ($option[1] === null) {
 322                        $option[1] = 'php://stdout';
 323                    }
 324
 325                    $this->arguments['coverageText']                   = $option[1];
 326                    $this->arguments['coverageTextShowUncoveredFiles'] = false;
 327                    $this->arguments['coverageTextShowOnlySummary']    = false;
 328                    break;
 329
 330                case '--coverage-xml':
 331                    $this->arguments['coverageXml'] = $option[1];
 332                    break;
 333
 334                case 'd':
 335                    $ini = explode('=', $option[1]);
 336
 337                    if (isset($ini[0])) {
 338                        if (isset($ini[1])) {
 339                            ini_set($ini[0], $ini[1]);
 340                        } else {
 341                            ini_set($ini[0], true);
 342                        }
 343                    }
 344                    break;
 345
 346                case '--debug':
 347                    $this->arguments['debug'] = true;
 348                    break;
 349
 350                case 'h':
 351                case '--help':
 352                    $this->showHelp();
 353                    exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
 354                    break;
 355
 356                case '--filter':
 357                    $this->arguments['filter'] = $option[1];
 358                    break;
 359
 360                case '--testsuite':
 361                    $this->arguments['testsuite'] = $option[1];
 362                    break;
 363
 364                case '--generate-configuration':
 365                    $this->printVersionString();
 366
 367                    printf(
 368                        "Generating phpunit.xml in %s\n\n",
 369                        getcwd()
 370                    );
 371
 372                    print 'Bootstrap script (relative to path shown above; default: vendor/autoload.php): ';
 373                    $bootstrapScript = trim(fgets(STDIN));
 374
 375                    print 'Tests directory (relative to path shown above; default: tests): ';
 376                    $testsDirectory = trim(fgets(STDIN));
 377
 378                    print 'Source directory (relative to path shown above; default: src): ';
 379                    $src = trim(fgets(STDIN));
 380
 381                    if ($bootstrapScript == '') {
 382                        $bootstrapScript = 'vendor/autoload.php';
 383                    }
 384
 385                    if ($testsDirectory == '') {
 386                        $testsDirectory = 'tests';
 387                    }
 388
 389                    if ($src == '') {
 390                        $src = 'src';
 391                    }
 392
 393                    $generator = new PHPUnit_Util_ConfigurationGenerator;
 394
 395                    file_put_contents(
 396                        'phpunit.xml',
 397                        $generator->generateDefaultConfiguration(
 398                            PHPUnit_Runner_Version::series(),
 399                            $bootstrapScript,
 400                            $testsDirectory,
 401                            $src
 402                        )
 403                    );
 404
 405                    printf(
 406                        "\nGenerated phpunit.xml in %s\n",
 407                        getcwd()
 408                    );
 409
 410                    exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
 411                    break;
 412
 413                case '--group':
 414                    $this->arguments['groups'] = explode(',', $option[1]);
 415                    break;
 416
 417                case '--exclude-group':
 418                    $this->arguments['excludeGroups'] = explode(
 419                        ',',
 420                        $option[1]
 421                    );
 422                    break;
 423
 424                case '--test-suffix':
 425                    $this->arguments['testSuffixes'] = explode(
 426                        ',',
 427                        $option[1]
 428                    );
 429                    break;
 430
 431                case '--include-path':
 432                    $includePath = $option[1];
 433                    break;
 434
 435                case '--list-groups':
 436                    $this->arguments['listGroups'] = true;
 437                    break;
 438
 439                case '--list-suites':
 440                    $this->arguments['listSuites'] = true;
 441                    break;
 442
 443                case '--printer':
 444                    $this->arguments['printer'] = $option[1];
 445                    break;
 446
 447                case '--loader':
 448                    $this->arguments['loader'] = $option[1];
 449                    break;
 450
 451                case '--log-json':
 452                    $this->arguments['jsonLogfile'] = $option[1];
 453                    break;
 454
 455                case '--log-junit':
 456                    $this->arguments['junitLogfile'] = $option[1];
 457                    break;
 458
 459                case '--log-tap':
 460                    $this->arguments['tapLogfile'] = $option[1];
 461                    break;
 462
 463                case '--log-teamcity':
 464                    $this->arguments['teamcityLogfile'] = $option[1];
 465                    break;
 466
 467                case '--process-isolation':
 468                    $this->arguments['processIsolation'] = true;
 469                    break;
 470
 471                case '--repeat':
 472                    $this->arguments['repeat'] = (int) $option[1];
 473                    break;
 474
 475                case '--stderr':
 476                    $this->arguments['stderr'] = true;
 477                    break;
 478
 479                case '--stop-on-error':
 480                    $this->arguments['stopOnError'] = true;
 481                    break;
 482
 483                case '--stop-on-failure':
 484                    $this->arguments['stopOnFailure'] = true;
 485                    break;
 486
 487                case '--stop-on-warning':
 488                    $this->arguments['stopOnWarning'] = true;
 489                    break;
 490
 491                case '--stop-on-incomplete':
 492                    $this->arguments['stopOnIncomplete'] = true;
 493                    break;
 494
 495                case '--stop-on-risky':
 496                    $this->arguments['stopOnRisky'] = true;
 497                    break;
 498
 499                case '--stop-on-skipped':
 500                    $this->arguments['stopOnSkipped'] = true;
 501                    break;
 502
 503                case '--fail-on-warning':
 504                    $this->arguments['failOnWarning'] = true;
 505                    break;
 506
 507                case '--fail-on-risky':
 508                    $this->arguments['failOnRisky'] = true;
 509                    break;
 510
 511                case '--tap':
 512                    $this->arguments['printer'] = 'PHPUnit_Util_Log_TAP';
 513                    break;
 514
 515                case '--teamcity':
 516                    $this->arguments['printer'] = 'PHPUnit_Util_Log_TeamCity';
 517                    break;
 518
 519                case '--testdox':
 520                    $this->arguments['printer'] = 'PHPUnit_Util_TestDox_ResultPrinter_Text';
 521                    break;
 522
 523                case '--testdox-group':
 524                    $this->arguments['testdoxGroups'] = explode(
 525                        ',',
 526                        $option[1]
 527                    );
 528                    break;
 529
 530                case '--testdox-exclude-group':
 531                    $this->arguments['testdoxExcludeGroups'] = explode(
 532                        ',',
 533                        $option[1]
 534                    );
 535                    break;
 536
 537                case '--testdox-html':
 538                    $this->arguments['testdoxHTMLFile'] = $option[1];
 539                    break;
 540
 541                case '--testdox-text':
 542                    $this->arguments['testdoxTextFile'] = $option[1];
 543                    break;
 544
 545                case '--testdox-xml':
 546                    $this->arguments['testdoxXMLFile'] = $option[1];
 547                    break;
 548
 549                case '--no-configuration':
 550                    $this->arguments['useDefaultConfiguration'] = false;
 551                    break;
 552
 553                case '--no-extensions':
 554                    $this->arguments['noExtensions'] = true;
 555                    break;
 556
 557                case '--no-coverage':
 558                    $this->arguments['noCoverage'] = true;
 559                    break;
 560
 561                case '--no-globals-backup':
 562                    $this->arguments['backupGlobals'] = false;
 563                    break;
 564
 565                case '--static-backup':
 566                    $this->arguments['backupStaticAttributes'] = true;
 567                    break;
 568
 569                case 'v':
 570                case '--verbose':
 571                    $this->arguments['verbose'] = true;
 572                    break;
 573
 574                case '--atleast-version':
 575                    exit(version_compare(PHPUnit_Runner_Version::id(), $option[1], '>=')
 576                        ? PHPUnit_TextUI_TestRunner::SUCCESS_EXIT
 577                        : PHPUnit_TextUI_TestRunner::FAILURE_EXIT
 578                    );
 579                    break;
 580
 581                case '--version':
 582                    $this->printVersionString();
 583                    exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
 584                    break;
 585
 586                case '--report-useless-tests':
 587                    $this->arguments['reportUselessTests'] = true;
 588                    break;
 589
 590                case '--strict-coverage':
 591                    $this->arguments['strictCoverage'] = true;
 592                    break;
 593
 594                case '--disable-coverage-ignore':
 595                    $this->arguments['disableCodeCoverageIgnore'] = true;
 596                    break;
 597
 598                case '--strict-global-state':
 599                    $this->arguments['beStrictAboutChangesToGlobalState'] = true;
 600                    break;
 601
 602                case '--disallow-test-output':
 603                    $this->arguments['disallowTestOutput'] = true;
 604                    break;
 605
 606                case '--disallow-resource-usage':
 607                    $this->arguments['beStrictAboutResourceUsageDuringSmallTests'] = true;
 608                    break;
 609
 610                case '--enforce-time-limit':
 611                    $this->arguments['enforceTimeLimit'] = true;
 612                    break;
 613
 614                case '--disallow-todo-tests':
 615                    $this->arguments['disallowTodoAnnotatedTests'] = true;
 616                    break;
 617
 618                case '--reverse-list':
 619                    $this->arguments['reverseList'] = true;
 620                    break;
 621
 622                case '--check-version':
 623                    $this->handleVersionCheck();
 624                    break;
 625
 626                case '--selfupdate':
 627                case '--self-update':
 628                    $this->handleSelfUpdate();
 629                    break;
 630
 631                case '--selfupgrade':
 632                case '--self-upgrade':
 633                    $this->handleSelfUpdate(true);
 634                    break;
 635
 636                case '--whitelist':
 637                    $this->arguments['whitelist'] = $option[1];
 638                    break;
 639
 640                default:
 641                    $optionName = str_replace('--', '', $option[0]);
 642
 643                    $handler = null;
 644                    if (isset($this->longOptions[$optionName])) {
 645                        $handler = $this->longOptions[$optionName];
 646                    } elseif (isset($this->longOptions[$optionName . '='])) {
 647                        $handler = $this->longOptions[$optionName . '='];
 648                    }
 649
 650                    if (isset($handler) && is_callable([$this, $handler])) {
 651                        $this->$handler($option[1]);
 652                    }
 653            }
 654        }
 655
 656        $this->handleCustomTestSuite();
 657
 658        if (!isset($this->arguments['test'])) {
 659            if (isset($this->options[1][0])) {
 660                $this->arguments['test'] = $this->options[1][0];
 661            }
 662
 663            if (isset($this->options[1][1])) {
 664                $this->arguments['testFile'] = realpath($this->options[1][1]);
 665            } else {
 666                $this->arguments['testFile'] = '';
 667            }
 668
 669            if (isset($this->arguments['test']) &&
 670                is_file($this->arguments['test']) &&
 671                substr($this->arguments['test'], -5, 5) != '.phpt') {
 672                $this->arguments['testFile'] = realpath($this->arguments['test']);
 673                $this->arguments['test']     = substr($this->arguments['test'], 0, strrpos($this->arguments['test'], '.'));
 674            }
 675        }
 676
 677        if (!isset($this->arguments['testSuffixes'])) {
 678            $this->arguments['testSuffixes'] = ['Test.php', '.phpt'];
 679        }
 680
 681        if (isset($includePath)) {
 682            ini_set(
 683                'include_path',
 684                $includePath . PATH_SEPARATOR . ini_get('include_path')
 685            );
 686        }
 687
 688        if ($this->arguments['loader'] !== null) {
 689            $this->arguments['loader'] = $this->handleLoader($this->arguments['loader']);
 690        }
 691
 692        if (isset($this->arguments['configuration']) &&
 693            is_dir($this->arguments['configuration'])) {
 694            $configurationFile = $this->arguments['configuration'] . '/phpunit.xml';
 695
 696            if (file_exists($configurationFile)) {
 697                $this->arguments['configuration'] = realpath(
 698                    $configurationFile
 699                );
 700            } elseif (file_exists($configurationFile . '.dist')) {
 701                $this->arguments['configuration'] = realpath(
 702                    $configurationFile . '.dist'
 703                );
 704            }
 705        } elseif (!isset($this->arguments['configuration']) &&
 706                  $this->arguments['useDefaultConfiguration']) {
 707            if (file_exists('phpunit.xml')) {
 708                $this->arguments['configuration'] = realpath('phpunit.xml');
 709            } elseif (file_exists('phpunit.xml.dist')) {
 710                $this->arguments['configuration'] = realpath(
 711                    'phpunit.xml.dist'
 712                );
 713            }
 714        }
 715
 716        if (isset($this->arguments['configuration'])) {
 717            try {
 718                $configuration = PHPUnit_Util_Configuration::getInstance(
 719                    $this->arguments['configuration']
 720                );
 721            } catch (Throwable $e) {
 722                print $e->getMessage() . "\n";
 723                exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
 724            } catch (Exception $e) {
 725                print $e->getMessage() . "\n";
 726                exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
 727            }
 728
 729            $phpunitConfiguration = $configuration->getPHPUnitConfiguration();
 730
 731            $configuration->handlePHPConfiguration();
 732
 733            /*
 734             * Issue #1216
 735             */
 736            if (isset($this->arguments['bootstrap'])) {
 737                $this->handleBootstrap($this->arguments['bootstrap']);
 738            } elseif (isset($phpunitConfiguration['bootstrap'])) {
 739                $this->handleBootstrap($phpunitConfiguration['bootstrap']);
 740            }
 741
 742            /*
 743             * Issue #657
 744             */
 745            if (isset($phpunitConfiguration['stderr']) && ! isset($this->arguments['stderr'])) {
 746                $this->arguments['stderr'] = $phpunitConfiguration['stderr'];
 747            }
 748
 749            if (isset($phpunitConfiguration['extensionsDirectory']) && !isset($this->arguments['noExtensions']) && extension_loaded('phar')) {
 750                $this->handleExtensions($phpunitConfiguration['extensionsDirectory']);
 751            }
 752
 753            if (isset($phpunitConfiguration['columns']) && ! isset($this->arguments['columns'])) {
 754                $this->arguments['columns'] = $phpunitConfiguration['columns'];
 755            }
 756
 757            if (!isset($this->arguments['printer']) && isset($phpunitConfiguration['printerClass'])) {
 758                if (isset($phpunitConfiguration['printerFile'])) {
 759                    $file = $phpunitConfiguration['printerFile'];
 760                } else {
 761                    $file = '';
 762                }
 763
 764                $this->arguments['printer'] = $this->handlePrinter(
 765                    $phpunitConfiguration['printerClass'],
 766                    $file
 767                );
 768            }
 769
 770            if (isset($phpunitConfiguration['testSuiteLoaderClass'])) {
 771                if (isset($phpunitConfiguration['testSuiteLoaderFile'])) {
 772                    $file = $phpunitConfiguration['testSuiteLoaderFile'];
 773                } else {
 774                    $file = '';
 775                }
 776
 777                $this->arguments['loader'] = $this->handleLoader(
 778                    $phpunitConfiguration['testSuiteLoaderClass'],
 779                    $file
 780                );
 781            }
 782
 783            if (!isset($this->arguments['test'])) {
 784                $testSuite = $configuration->getTestSuiteConfiguration(isset($this->arguments['testsuite']) ? $this->arguments['testsuite'] : null);
 785
 786                if ($testSuite !== null) {
 787                    $this->arguments['test'] = $testSuite;
 788                }
 789            }
 790        } elseif (isset($this->arguments['bootstrap'])) {
 791            $this->handleBootstrap($this->arguments['bootstrap']);
 792        }
 793
 794        if (isset($this->arguments['printer']) &&
 795            is_string($this->arguments['printer'])) {
 796            $this->arguments['printer'] = $this->handlePrinter($this->arguments['printer']);
 797        }
 798
 799        if (isset($this->arguments['test']) && is_string($this->arguments['test']) && substr($this->arguments['test'], -5, 5) == '.phpt') {
 800            $test = new PHPUnit_Extensions_PhptTestCase($this->arguments['test']);
 801
 802            $this->arguments['test'] = new PHPUnit_Framework_TestSuite;
 803            $this->arguments['test']->addTest($test);
 804        }
 805
 806        if (!isset($this->arguments['test']) ||
 807            (isset($this->arguments['testDatabaseLogRevision']) && !isset($this->arguments['testDatabaseDSN']))) {
 808            $this->showHelp();
 809            exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
 810        }
 811    }
 812
 813    /**
 814     * Handles the loading of the PHPUnit_Runner_TestSuiteLoader implementation.
 815     *
 816     * @param string $loaderClass
 817     * @param string $loaderFile
 818     *
 819     * @return PHPUnit_Runner_TestSuiteLoader
 820     */
 821    protected function handleLoader($loaderClass, $loaderFile = '')
 822    {
 823        if (!class_exists($loaderClass, false)) {
 824            if ($loaderFile == '') {
 825                $loaderFile = PHPUnit_Util_Filesystem::classNameToFilename(
 826                    $loaderClass
 827                );
 828            }
 829
 830            $loaderFile = stream_resolve_include_path($loaderFile);
 831
 832            if ($loaderFile) {
 833                require $loaderFile;
 834            }
 835        }
 836
 837        if (class_exists($loaderClass, false)) {
 838            $class = new ReflectionClass($loaderClass);
 839
 840            if ($class->implementsInterface('PHPUnit_Runner_TestSuiteLoader') &&
 841                $class->isInstantiable()) {
 842                return $class->newInstance();
 843            }
 844        }
 845
 846        if ($loaderClass == 'PHPUnit_Runner_StandardTestSuiteLoader') {
 847            return;
 848        }
 849
 850        $this->showError(
 851            sprintf(
 852                'Could not use "%s" as loader.',
 853                $loaderClass
 854            )
 855        );
 856    }
 857
 858    /**
 859     * Handles the loading of the PHPUnit_Util_Printer implementation.
 860     *
 861     * @param string $printerClass
 862     * @param string $printerFile
 863     *
 864     * @return PHPUnit_Util_Printer|string
 865     */
 866    protected function handlePrinter($printerClass, $printerFile = '')
 867    {
 868        if (!class_exists($printerClass, false)) {
 869            if ($printerFile == '') {
 870                $printerFile = PHPUnit_Util_Filesystem::classNameToFilename(
 871                    $printerClass
 872                );
 873            }
 874
 875            $printerFile = stream_resolve_include_path($printerFile);
 876
 877            if ($printerFile) {
 878                require $printerFile;
 879            }
 880        }
 881
 882        if (class_exists($printerClass)) {
 883            $class = new ReflectionClass($printerClass);
 884
 885            if ($class->implementsInterface('PHPUnit_Framework_TestListener') &&
 886                $class->isSubclassOf('PHPUnit_Util_Printer') &&
 887                $class->isInstantiable()) {
 888                if ($class->isSubclassOf('PHPUnit_TextUI_ResultPrinter')) {
 889                    return $printerClass;
 890                }
 891
 892                $outputStream = isset($this->arguments['stderr']) ? 'php://stderr' : null;
 893
 894                return $class->newInstance($outputStream);
 895            }
 896        }
 897
 898        $this->showError(
 899            sprintf(
 900                'Could not use "%s" as printer.',
 901                $printerClass
 902            )
 903        );
 904    }
 905
 906    /**
 907     * Loads a bootstrap file.
 908     *
 909     * @param string $filename
 910     */
 911    protected function handleBootstrap($filename)
 912    {
 913        try {
 914            PHPUnit_Util_Fileloader::checkAndLoad($filename);
 915        } catch (PHPUnit_Framework_Exception $e) {
 916            $this->showError($e->getMessage());
 917        }
 918    }
 919
 920    protected function handleSelfUpdate($upgrade = false)
 921    {
 922        $this->printVersionString();
 923
 924        if ($upgrade) {
 925            print "Warning: Deprecated --self-upgrade used\n\n";
 926        } else {
 927            print "Warning: Deprecated --self-update used\n\n";
 928        }
 929
 930        $localFilename = realpath($_SERVER['argv'][0]);
 931
 932        if (!is_writable($localFilename)) {
 933            print 'No write permission to update ' . $localFilename . "\n";
 934            exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
 935        }
 936
 937        if (!extension_loaded('openssl')) {
 938            print "The OpenSSL extension is not loaded.\n";
 939            exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
 940        }
 941
 942        if (!$upgrade) {
 943            $remoteFilename = sprintf(
 944                'https://phar.phpunit.de/phpunit-%s.phar',
 945                file_get_contents(
 946                    sprintf(
 947                        'https://phar.phpunit.de/latest-version-of/phpunit-%s',
 948                        PHPUnit_Runner_Version::series()
 949                    )
 950                )
 951            );
 952        } else {
 953            $remoteFilename = sprintf(
 954                'https://phar.phpunit.de/phpunit%s.phar',
 955                PHPUnit_Runner_Version::getReleaseChannel()
 956            );
 957        }
 958
 959        $tempFilename = tempnam(sys_get_temp_dir(), 'phpunit') . '.phar';
 960
 961        // Workaround for https://bugs.php.net/bug.php?id=65538
 962        $caFile = dirname($tempFilename) . '/ca.pem';
 963        copy(__PHPUNIT_PHAR_ROOT__ . '/ca.pem', $caFile);
 964
 965        print 'Updating the PHPUnit PHAR ... ';
 966
 967        $options = [
 968            'ssl' => [
 969                'allow_self_signed' => false,
 970                'cafile'            => $caFile,
 971                'verify_peer'       => true
 972            ]
 973        ];
 974
 975        file_put_contents(
 976            $tempFilename,
 977            file_get_contents(
 978                $remoteFilename,
 979                false,
 980                stream_context_create($options)
 981            )
 982        );
 983
 984        chmod($tempFilename, 0777 & ~umask());
 985
 986        try {
 987            $phar = new Phar($tempFilename);
 988            unset($phar);
 989            rename($tempFilename, $localFilename);
 990            unlink($caFile);
 991        } catch (Throwable $_e) {
 992            $e = $_e;
 993        } catch (Exception $_e) {
 994            $e = $_e;
 995        }
 996
 997        if (isset($e)) {
 998            unlink($caFile);
 999            unlink($tempFilename);
1000            print " done\n\n" . $e->getMessage() . "\n";
1001            exit(2);
1002        }
1003
1004        print " done\n";
1005        exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
1006    }
1007
1008    protected function handleVersionCheck()
1009    {
1010        $this->printVersionString();
1011
1012        $latestVersion = file_get_contents('https://phar.phpunit.de/latest-version-of/phpunit');
1013        $isOutdated    = version_compare($latestVersion, PHPUnit_Runner_Version::id(), '>');
1014
1015        if ($isOutdated) {
1016            print "You are not using the latest version of PHPUnit.\n";
1017            print 'Use "phpunit --self-upgrade" to install PHPUnit ' . $latestVersion . "\n";
1018        } else {
1019            print "You are using the latest version of PHPUnit.\n";
1020        }
1021
1022        exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
1023    }
1024
1025    /**
1026     * Show the help message.
1027     */
1028    protected function showHelp()
1029    {
1030        $this->printVersionString();
1031
1032        print <<<EOT
1033Usage: phpunit [options] UnitTest [UnitTest.php]
1034       phpunit [options] <directory>
1035
1036Code Coverage Options:
1037
1038  --coverage-clover <file>  Generate code coverage report in Clover XML format.
1039  --coverage-crap4j <file>  Generate code coverage report in Crap4J XML format.
1040  --coverage-html <dir>     Generate code coverage report in HTML format.
1041  --coverage-php <file>     Export PHP_CodeCoverage object to file.
1042  --coverage-text=<file>    Generate code coverage report in text format.
1043                            Default: Standard output.
1044  --coverage-xml <dir>      Generate code coverage report in PHPUnit XML format.
1045  --whitelist <dir>         Whitelist <dir> for code coverage analysis.
1046  --disable-coverage-ignore Disable annotations for ignoring code coverage.
1047
1048Logging Options:
1049
1050  --log-junit <file>        Log test execution in JUnit XML format to file.
1051  --log-teamcity <file>     Log test execution in TeamCity format to file.
1052  --testdox-html <file>     Write agile documentation in HTML format to file.
1053  --testdox-text <file>     Write agile documentation in Text format to file.
1054  --testdox-xml <file>      Write agile documentation in XML format to file.
1055  --reverse-list            Print defects in reverse order
1056
1057Test Selection Options:
1058
1059  --filter <pattern>        Filter which tests to run.
1060  --testsuite <name>        Filter which testsuite to run.
1061  --group ...               Only runs tests from the specified group(s).
1062  --exclude-group ...       Exclude tests from the specified group(s).
1063  --list-groups             List available test groups.
1064  --list-suites             List available test suites.
1065  --test-suffix ...         Only search for test in files with specified
1066                            suffix(es). Default: Test.php,.phpt
1067
1068Test Execution Options:
1069
1070  --report-useless-tests    Be strict about tests that do not test anything.
1071  --strict-coverage         Be strict about @covers annotation usage.
1072  --strict-global-state     Be strict about changes to global state
1073  --disallow-test-output    Be strict about output during tests.
1074  --disallow-resource-usage Be strict about resource usage during small tests.
1075  --enforce-time-limit      Enforce time limit based on test size.
1076  --disallow-todo-tests     Disallow @todo-annotated tests.
1077
1078  --process-isolation       Run each test in a separate PHP process.
1079  --no-globals-backup       Do not backup and restore \$GLOBALS for each test.
1080  --static-backup           Backup and restore static attributes for each test.
1081
1082  --colors=<flag>           Use colors in output ("never", "auto" or "always").
1083  --columns <n>             Number of columns to use for progress output.
1084  --columns max             Use maximum number of columns for progress output.
1085  --stderr                  Write to STDERR instead of STDOUT.
1086  --stop-on-error           Stop execution upon first error.
1087  --stop-on-failure         Stop execution upon first error or failure.
1088  --stop-on-warning         Stop execution upon first warning.
1089  --stop-on-risky           Stop execution upon first risky test.
1090  --stop-on-skipped         Stop execution upon first skipped test.
1091  --stop-on-incomplete      Stop execution upon first incomplete test.
1092  --fail-on-warning         Treat tests with warnings as failures.
1093  --fail-on-risky           Treat risky tests as failures.
1094  -v|--verbose              Output more verbose information.
1095  --debug                   Display debugging information during test execution.
1096
1097  --loader <loader>         TestSuiteLoader implementation to use.
1098  --repeat <times>          Runs the test(s) repeatedly.
1099  --teamcity                Report test execution progress in TeamCity format.
1100  --testdox                 Report test execution progress in TestDox format.
1101  --testdox-group           Only include tests from the specified group(s).
1102  --testdox-exclude-group   Exclude tests from the specified group(s).
1103  --printer <printer>       TestListener implementation to use.
1104
1105Configuration Options:
1106
1107  --bootstrap <file>        A "bootstrap" PHP file that is run before the tests.
1108  -c|--configuration <file> Read configuration from XML file.
1109  --no-configuration        Ignore default configuration file (phpunit.xml).
1110  --no-coverage             Ignore code coverage configuration.
1111  --no-extensions           Do not load PHPUnit extensions.
1112  --include-path <path(s)>  Prepend PHP's include_path with given path(s).
1113  -d key[=value]            Sets a php.ini value.
1114  --generate-configuration  Generate configuration file with suggested settings.
1115
1116Miscellaneous Options:
1117
1118  -h|--help                 Prints this usage information.
1119  --version                 Prints the version and exits.
1120  --atleast-version <min>   Checks that version is greater than min and exits.
1121
1122EOT;
1123
1124        if (defined('__PHPUNIT_PHAR__')) {
1125            print "\n  --check-version           Check whether PHPUnit is the latest version.";
1126        }
1127    }
1128
1129    /**
1130     * Custom callback for test suite discovery.
1131     */
1132    protected function handleCustomTestSuite()
1133    {
1134    }
1135
1136    private function printVersionString()
1137    {
1138        if ($this->versionStringPrinted) {
1139            return;
1140        }
1141
1142        print PHPUnit_Runner_Version::getVersionString() . "\n\n";
1143
1144        $this->versionStringPrinted = true;
1145    }
1146
1147    /**
1148     * @param string $message
1149     */
1150    private function showError($message)
1151    {
1152        $this->printVersionString();
1153
1154        print $message . "\n";
1155
1156        exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
1157    }
1158
1159    /**
1160     * @param string $directory
1161     */
1162    private function handleExtensions($directory)
1163    {
1164        $facade = new File_Iterator_Facade;
1165
1166        foreach ($facade->getFilesAsArray($directory, '.phar') as $file) {
1167            require $file;
1168
1169            $this->arguments['loadedExtensions'][] = $file;
1170        }
1171    }
1172}