diff --git a/src/TextUI/Command.php b/src/TextUI/Command.php index 346092a1510..e0ff1061fc1 100644 --- a/src/TextUI/Command.php +++ b/src/TextUI/Command.php @@ -1083,112 +1083,7 @@ protected function handleVersionCheck(): void protected function showHelp(): void { $this->printVersionString(); - - print << - -Code Coverage Options: - - --coverage-clover Generate code coverage report in Clover XML format - --coverage-crap4j Generate code coverage report in Crap4J XML format - --coverage-html Generate code coverage report in HTML format - --coverage-php Export PHP_CodeCoverage object to file - --coverage-text= Generate code coverage report in text format - Default: Standard output - --coverage-xml Generate code coverage report in PHPUnit XML format - --whitelist Whitelist for code coverage analysis - --disable-coverage-ignore Disable annotations for ignoring code coverage - --no-coverage Ignore code coverage configuration - --dump-xdebug-filter Generate script to set Xdebug code coverage filter - -Logging Options: - - --log-junit Log test execution in JUnit XML format to file - --log-teamcity Log test execution in TeamCity format to file - --testdox-html Write agile documentation in HTML format to file - --testdox-text Write agile documentation in Text format to file - --testdox-xml Write agile documentation in XML format to file - --reverse-list Print defects in reverse order - -Test Selection Options: - - --filter Filter which tests to run - --testsuite Filter which testsuite to run - --group ... Only runs tests from the specified group(s) - --exclude-group ... Exclude tests from the specified group(s) - --list-groups List available test groups - --list-suites List available test suites - --list-tests List available tests - --list-tests-xml List available tests in XML format - --test-suffix ... Only search for test in files with specified - suffix(es). Default: Test.php,.phpt - -Test Execution Options: - - --dont-report-useless-tests Do not report tests that do not test anything - --strict-coverage Be strict about @covers annotation usage - --strict-global-state Be strict about changes to global state - --disallow-test-output Be strict about output during tests - --disallow-resource-usage Be strict about resource usage during small tests - --enforce-time-limit Enforce time limit based on test size - --default-time-limit= Timeout in seconds for tests without @small, @medium or @large - --disallow-todo-tests Disallow @todo-annotated tests - - --process-isolation Run each test in a separate PHP process - --globals-backup Backup and restore \$GLOBALS for each test - --static-backup Backup and restore static attributes for each test - - --colors= Use colors in output ("never", "auto" or "always") - --columns Number of columns to use for progress output - --columns max Use maximum number of columns for progress output - --stderr Write to STDERR instead of STDOUT - --stop-on-defect Stop execution upon first not-passed test - --stop-on-error Stop execution upon first error - --stop-on-failure Stop execution upon first error or failure - --stop-on-warning Stop execution upon first warning - --stop-on-risky Stop execution upon first risky test - --stop-on-skipped Stop execution upon first skipped test - --stop-on-incomplete Stop execution upon first incomplete test - --fail-on-warning Treat tests with warnings as failures - --fail-on-risky Treat risky tests as failures - -v|--verbose Output more verbose information - --debug Display debugging information - - --loader TestSuiteLoader implementation to use - --repeat Runs the test(s) repeatedly - --teamcity Report test execution progress in TeamCity format - --testdox Report test execution progress in TestDox format - --testdox-group Only include tests from the specified group(s) - --testdox-exclude-group Exclude tests from the specified group(s) - --printer TestListener implementation to use - - --order-by= Run tests in order: default|reverse|random|defects|no-depends - --random-order-seed= Use a specific random seed for random order - --cache-result Write test results to cache file - --do-not-cache-result Do not write test results to cache file - -Configuration Options: - - --prepend A PHP script that is included as early as possible - --bootstrap A PHP script that is included before the tests run - -c|--configuration Read configuration from XML file - --no-configuration Ignore default configuration file (phpunit.xml) - --no-logging Ignore logging configuration - --no-extensions Do not load PHPUnit extensions - --include-path Prepend PHP's include_path with given path(s) - -d key[=value] Sets a php.ini value - --generate-configuration Generate configuration file with suggested settings - --cache-result-file= Specify result cache path and filename - -Miscellaneous Options: - - -h|--help Prints this usage information - --version Prints the version and exits - --atleast-version Checks that version is greater than min and exits - --check-version Check whether PHPUnit is the latest version - -EOT; + (new \Help())->writeToConsole(); } /** diff --git a/src/Util/Help.php b/src/Util/Help.php new file mode 100644 index 00000000000..55b31468806 --- /dev/null +++ b/src/Util/Help.php @@ -0,0 +1,244 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use PHPUnit\Util\Color; +use SebastianBergmann\Environment\Console; + +class Help +{ + private const LEFT_MARGIN = ' '; + + private const HELP_TEXT = [ + 'Usage' => [ + ['text' => 'phpunit [options] UnitTest [UnitTest.php]'], + ['text' => 'phpunit [options] '], + ], + 'Code Coverage Options' => [ + ['arg' => '--coverage-clover ', 'desc' => 'Generate code coverage report in Clover XML format'], + ['arg' => '--coverage-crap4j ', 'desc' => 'Generate code coverage report in Crap4J XML format'], + ['arg' => '--coverage-html ', 'desc' => 'Generate code coverage report in HTML format'], + ['arg' => '--coverage-php ', 'desc' => 'Export PHP_CodeCoverage object to file'], + ['arg' => '--coverage-text=', 'desc' => 'Generate code coverage report in text format [default: standard output]'], + ['arg' => '--coverage-xml ', 'desc' => 'Generate code coverage report in PHPUnit XML format'], + ['arg' => '--whitelist ', 'desc' => 'Whitelist for code coverage analysis'], + ['arg' => '--disable-coverage-ignore', 'desc' => 'Disable annotations for ignoring code coverage'], + ['arg' => '--no-coverage', 'desc' => 'Ignore code coverage configuration'], + ['arg' => '--dump-xdebug-filter ', 'desc' => 'Generate script to set Xdebug code coverage filter'], + ], + + 'Logging Options' => [ + ['arg' => '--log-junit ', 'desc' => 'Log test execution in JUnit XML format to file'], + ['arg' => '--log-teamcity ', 'desc' => 'Log test execution in TeamCity format to file'], + ['arg' => '--testdox-html ', 'desc' => 'Write agile documentation in HTML format to file'], + ['arg' => '--testdox-text ', 'desc' => 'Write agile documentation in Text format to file'], + ['arg' => '--testdox-xml ', 'desc' => 'Write agile documentation in XML format to file'], + ['arg' => '--reverse-list', 'desc' => 'Print defects in reverse order'], + ], + + 'Test Selection Options' => [ + ['arg' => '--filter ', 'desc' => 'Filter which tests to run'], + ['arg' => '--testsuite ', 'desc' => 'Filter which testsuite to run'], + ['arg' => '--group ', 'desc' => 'Only runs tests from the specified group(s)'], + ['arg' => '--exclude-group ', 'desc' => 'Exclude tests from the specified group(s)'], + ['arg' => '--list-groups', 'desc' => 'List available test groups'], + ['arg' => '--list-suites', 'desc' => 'List available test suites'], + ['arg' => '--list-tests', 'desc' => 'List available tests'], + ['arg' => '--list-tests-xml ', 'desc' => 'List available tests in XML format'], + ['arg' => '--test-suffix ', 'desc' => 'Only search for test in files with specified suffix(es). Default: Test.php,.phpt'], + ], + + 'Test Execution Options' => [ + ['arg' => '--dont-report-useless-tests', 'desc' => 'Do not report tests that do not test anything'], + ['arg' => '--strict-coverage', 'desc' => 'Be strict about @covers annotation usage'], + ['arg' => '--strict-global-state', 'desc' => 'Be strict about changes to global state'], + ['arg' => '--disallow-test-output', 'desc' => 'Be strict about output during tests'], + ['arg' => '--disallow-resource-usage', 'desc' => 'Be strict about resource usage during small tests'], + ['arg' => '--enforce-time-limit', 'desc' => 'Enforce time limit based on test size'], + ['arg' => '--default-time-limit=', 'desc' => 'Timeout in seconds for tests without @small, @medium or @large'], + ['arg' => '--disallow-todo-tests', 'desc' => 'Disallow @todo-annotated tests'], + ['spacer' => ''], + + ['arg' => '--process-isolation', 'desc' => 'Run each test in a separate PHP process'], + ['arg' => '--globals-backup', 'desc' => 'Backup and restore $GLOBALS for each test'], + ['arg' => '--static-backup', 'desc' => 'Backup and restore static attributes for each test'], + ['spacer' => ''], + + ['arg' => '--colors=', 'desc' => 'Use colors in output ("never", "auto" or "always")'], + ['arg' => '--columns ', 'desc' => 'Number of columns to use for progress output'], + ['arg' => '--columns max', 'desc' => 'Use maximum number of columns for progress output'], + ['arg' => '--stderr', 'desc' => 'Write to STDERR instead of STDOUT'], + ['arg' => '--stop-on-defect', 'desc' => 'Stop execution upon first not-passed test'], + ['arg' => '--stop-on-error', 'desc' => 'Stop execution upon first error'], + ['arg' => '--stop-on-failure', 'desc' => 'Stop execution upon first error or failure'], + ['arg' => '--stop-on-warning', 'desc' => 'Stop execution upon first warning'], + ['arg' => '--stop-on-risky', 'desc' => 'Stop execution upon first risky test'], + ['arg' => '--stop-on-skipped', 'desc' => 'Stop execution upon first skipped test'], + ['arg' => '--stop-on-incomplete', 'desc' => 'Stop execution upon first incomplete test'], + ['arg' => '--fail-on-warning', 'desc' => 'Treat tests with warnings as failures'], + ['arg' => '--fail-on-risky', 'desc' => 'Treat risky tests as failures'], + ['arg' => '-v|--verbose', 'desc' => 'Output more verbose information'], + ['arg' => '--debug', 'desc' => 'Display debugging information'], + ['spacer' => ''], + + ['arg' => '--loader ', 'desc' => 'TestSuiteLoader implementation to use'], + ['arg' => '--repeat ', 'desc' => 'Runs the test(s) repeatedly'], + ['arg' => '--teamcity', 'desc' => 'Report test execution progress in TeamCity format'], + ['arg' => '--testdox', 'desc' => 'Report test execution progress in TestDox format'], + ['arg' => '--testdox-group', 'desc' => 'Only include tests from the specified group(s)'], + ['arg' => '--testdox-exclude-group', 'desc' => 'Exclude tests from the specified group(s)'], + ['arg' => '--printer ', 'desc' => 'TestListener implementation to use'], + ['spacer' => ''], + + ['arg' => '--order-by=', 'desc' => 'Run tests in order: default|reverse|random|defects|no-depends'], + ['arg' => '--random-order-seed=', 'desc' => 'Use a specific random seed for random order'], + ['arg' => '--cache-result', 'desc' => 'Write test results to cache file'], + ['arg' => '--do-not-cache-result', 'desc' => 'Do not write test results to cache file'], + ], + + 'Configuration Options' => [ + ['arg' => '--prepend ', 'desc' => 'A PHP script that is included as early as possible'], + ['arg' => '--bootstrap ', 'desc' => 'A PHP script that is included before the tests run'], + ['arg' => '-c|--configuration ', 'desc' => 'Read configuration from XML file'], + ['arg' => '--no-configuration', 'desc' => 'Ignore default configuration file (phpunit.xml)'], + ['arg' => '--no-logging', 'desc' => 'Ignore logging configuration'], + ['arg' => '--no-extensions', 'desc' => 'Do not load PHPUnit extensions'], + ['arg' => '--include-path ', 'desc' => 'Prepend PHP\'s include_path with given path(s)'], + ['arg' => '-d ', 'desc' => 'Sets a php.ini value'], + ['arg' => '--generate-configuration', 'desc' => 'Generate configuration file with suggested settings'], + ['arg' => '--cache-result-file=', 'desc' => 'Specify result cache path and filename'], + ], + + 'Miscellaneous Options' => [ + ['arg' => '-h|--help', 'desc' => 'Prints this usage information'], + ['arg' => '--version', 'desc' => 'Prints the version and exits'], + ['arg' => '--atleast-version ', 'desc' => 'Checks that version is greater than min and exits'], + ['arg' => '--check-version', 'desc' => 'Check whether PHPUnit is the latest version'], + ], + + ]; + + /** + * @var int Number of columns required to write the longest option name to the console + */ + private $maxArgLength = 0; + + /** + * @var int Number of columns left for the description field after padding and option + */ + private $maxDescLength = 0; + + /** + * @var bool Use color highlights for sections, options and parameters + */ + private $hasColor = false; + + public function __construct(?int $width = null, ?bool $withColor = null) + { + if ($width === null || $withColor === null) { + $console = new Console(); + } + + if ($withColor === null) { + $this->hasColor = $console->hasColorSupport(); + } else { + $this->hasColor = $withColor; + } + + foreach (self::HELP_TEXT as $section => $options) { + foreach ($options as $option) { + if (isset($option['arg'])) { + $this->maxArgLength = \max($this->maxArgLength, \strlen($option['arg']) ?? 0); + } + } + } + + if ($width === null) { + $width = $console->getNumberOfColumns(); + } + $this->maxDescLength = $width - $this->maxArgLength - 4; + } + + /** + * Write the help file to the CLI, adapting width and colors to the console + */ + public function writeToConsole(): void + { + if ($this->hasColor) { + $this->writeWithColor(); + } else { + $this->writePlaintext(); + } + } + + private function writePlaintext(): void + { + foreach (self::HELP_TEXT as $section => $options) { + print "$section:" . \PHP_EOL; + + if ($section !== 'Usage') { + print \PHP_EOL; + } + + foreach ($options as $option) { + if (isset($option['spacer'])) { + print \PHP_EOL; + } + + if (isset($option['text'])) { + print self::LEFT_MARGIN . $option['text'] . \PHP_EOL; + } + + if (isset($option['arg'])) { + $arg = \str_pad($option['arg'], $this->maxArgLength); + print self::LEFT_MARGIN . $arg . ' ' . $option['desc'] . \PHP_EOL; + } + } + + print \PHP_EOL; + } + } + + private function writeWithColor(): void + { + foreach (self::HELP_TEXT as $section => $options) { + print Color::colorize('fg-yellow', "$section:") . \PHP_EOL; + + foreach ($options as $option) { + if (isset($option['spacer'])) { + print \PHP_EOL; + } + + if (isset($option['text'])) { + print self::LEFT_MARGIN . $option['text'] . \PHP_EOL; + } + + if (isset($option['arg'])) { + $arg = Color::colorize('fg-green', \str_pad($option['arg'], $this->maxArgLength)); + $arg = \preg_replace_callback( + '/(<[^>]+>)/', + function ($matches) { + return Color::colorize('fg-cyan', $matches[0]); + }, + $arg + ); + $desc = \explode(\PHP_EOL, \wordwrap($option['desc'], $this->maxDescLength, \PHP_EOL)); + + print self::LEFT_MARGIN . $arg . ' ' . $desc[0] . \PHP_EOL; + + for ($i = 1; $i < \count($desc); $i++) { + print \str_repeat(' ', $this->maxArgLength + 3) . $desc[$i] . \PHP_EOL; + } + } + } + + print \PHP_EOL; + } + } +} diff --git a/tests/end-to-end/cli/_files/output-cli-help-color.txt b/tests/end-to-end/cli/_files/output-cli-help-color.txt new file mode 100644 index 00000000000..ab5dbec3f43 --- /dev/null +++ b/tests/end-to-end/cli/_files/output-cli-help-color.txt @@ -0,0 +1,132 @@ +Usage: + phpunit [options] UnitTest [UnitTest.php] + phpunit [options] + +Code Coverage Options: + --coverage-clover   Generate code coverage report in Clover + XML format + --coverage-crap4j   Generate code coverage report in Crap4J + XML format + --coverage-html   Generate code coverage report in HTML + format + --coverage-php   Export PHP_CodeCoverage object to file + --coverage-text=  Generate code coverage report in text + format [default: standard output] + --coverage-xml   Generate code coverage report in PHPUnit + XML format + --whitelist   Whitelist for code coverage + analysis + --disable-coverage-ignore  Disable annotations for ignoring code + coverage + --no-coverage  Ignore code coverage configuration + --dump-xdebug-filter  Generate script to set Xdebug code + coverage filter + +Logging Options: + --log-junit   Log test execution in JUnit XML format to + file + --log-teamcity   Log test execution in TeamCity format to + file + --testdox-html   Write agile documentation in HTML format + to file + --testdox-text   Write agile documentation in Text format + to file + --testdox-xml   Write agile documentation in XML format + to file + --reverse-list  Print defects in reverse order + +Test Selection Options: + --filter   Filter which tests to run + --testsuite   Filter which testsuite to run + --group   Only runs tests from the specified + group(s) + --exclude-group   Exclude tests from the specified group(s) + --list-groups  List available test groups + --list-suites  List available test suites + --list-tests  List available tests + --list-tests-xml   List available tests in XML format + --test-suffix   Only search for test in files with + specified suffix(es). Default: + Test.php,.phpt + +Test Execution Options: + --dont-report-useless-tests Do not report tests that do not test + anything + --strict-coverage  Be strict about @covers annotation usage + --strict-global-state  Be strict about changes to global state + --disallow-test-output  Be strict about output during tests + --disallow-resource-usage  Be strict about resource usage during + small tests + --enforce-time-limit  Enforce time limit based on test size + --default-time-limit=  Timeout in seconds for tests without + @small, @medium or @large + --disallow-todo-tests  Disallow @todo-annotated tests + + --process-isolation  Run each test in a separate PHP process + --globals-backup  Backup and restore $GLOBALS for each test + --static-backup  Backup and restore static attributes for + each test + + --colors=  Use colors in output ("never", "auto" or + "always") + --columns   Number of columns to use for progress + output + --columns max  Use maximum number of columns for + progress output + --stderr  Write to STDERR instead of STDOUT + --stop-on-defect  Stop execution upon first not-passed test + --stop-on-error  Stop execution upon first error + --stop-on-failure  Stop execution upon first error or + failure + --stop-on-warning  Stop execution upon first warning + --stop-on-risky  Stop execution upon first risky test + --stop-on-skipped  Stop execution upon first skipped test + --stop-on-incomplete  Stop execution upon first incomplete test + --fail-on-warning  Treat tests with warnings as failures + --fail-on-risky  Treat risky tests as failures + -v|--verbose  Output more verbose information + --debug  Display debugging information + + --loader   TestSuiteLoader implementation to use + --repeat   Runs the test(s) repeatedly + --teamcity  Report test execution progress in + TeamCity format + --testdox  Report test execution progress in TestDox + format + --testdox-group  Only include tests from the specified + group(s) + --testdox-exclude-group  Exclude tests from the specified group(s) + --printer   TestListener implementation to use + + --order-by=  Run tests in order: + default|reverse|random|defects|no-depends + --random-order-seed=  Use a specific random seed for random + order + --cache-result  Write test results to cache file + --do-not-cache-result  Do not write test results to cache file + +Configuration Options: + --prepend   A PHP script that is included as early as + possible + --bootstrap   A PHP script that is included before the + tests run + -c|--configuration   Read configuration from XML file + --no-configuration  Ignore default configuration file + (phpunit.xml) + --no-logging  Ignore logging configuration + --no-extensions  Do not load PHPUnit extensions + --include-path   Prepend PHP's include_path with given + path(s) + -d   Sets a php.ini value + --generate-configuration  Generate configuration file with + suggested settings + --cache-result-file=  Specify result cache path and filename + +Miscellaneous Options: + -h|--help  Prints this usage information + --version  Prints the version and exits + --atleast-version   Checks that version is greater than min + and exits + --check-version  Check whether PHPUnit is the latest + version + diff --git a/tests/end-to-end/cli/_files/output-cli-usage.txt b/tests/end-to-end/cli/_files/output-cli-usage.txt index 240225ced97..5134d0dcee3 100644 --- a/tests/end-to-end/cli/_files/output-cli-usage.txt +++ b/tests/end-to-end/cli/_files/output-cli-usage.txt @@ -1,7 +1,8 @@ PHPUnit %s by Sebastian Bergmann and contributors. -Usage: phpunit [options] UnitTest [UnitTest.php] - phpunit [options] +Usage: + phpunit [options] UnitTest [UnitTest.php] + phpunit [options] Code Coverage Options: @@ -9,8 +10,7 @@ Code Coverage Options: --coverage-crap4j Generate code coverage report in Crap4J XML format --coverage-html Generate code coverage report in HTML format --coverage-php Export PHP_CodeCoverage object to file - --coverage-text= Generate code coverage report in text format - Default: Standard output + --coverage-text= Generate code coverage report in text format [default: standard output] --coverage-xml Generate code coverage report in PHPUnit XML format --whitelist Whitelist for code coverage analysis --disable-coverage-ignore Disable annotations for ignoring code coverage @@ -29,15 +29,14 @@ Logging Options: Test Selection Options: --filter Filter which tests to run - --testsuite Filter which testsuite to run - --group ... Only runs tests from the specified group(s) - --exclude-group ... Exclude tests from the specified group(s) + --testsuite Filter which testsuite to run + --group Only runs tests from the specified group(s) + --exclude-group Exclude tests from the specified group(s) --list-groups List available test groups --list-suites List available test suites --list-tests List available tests --list-tests-xml List available tests in XML format - --test-suffix ... Only search for test in files with specified - suffix(es). Default: Test.php,.phpt + --test-suffix Only search for test in files with specified suffix(es). Default: Test.php,.phpt Test Execution Options: @@ -92,7 +91,7 @@ Configuration Options: --no-logging Ignore logging configuration --no-extensions Do not load PHPUnit extensions --include-path Prepend PHP's include_path with given path(s) - -d key[=value] Sets a php.ini value + -d Sets a php.ini value --generate-configuration Generate configuration file with suggested settings --cache-result-file= Specify result cache path and filename diff --git a/tests/end-to-end/cli/help-color.phpt b/tests/end-to-end/cli/help-color.phpt new file mode 100644 index 00000000000..633d1aef46d --- /dev/null +++ b/tests/end-to-end/cli/help-color.phpt @@ -0,0 +1,11 @@ +--TEST-- +phpunit --help +--ARGS-- +--no-configuration --help +--FILE-- +writeToConsole(); +--EXPECTF_EXTERNAL-- +_files/output-cli-help-color.txt