Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4180852
Command.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
30 KB
Referenced Files
None
Subscribers
None
Command.php
View Options
<?php
declare
(
strict_types
=
1
);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace
PHPUnit\TextUI
;
use
const
PATH_SEPARATOR
;
use
const
PHP_EOL
;
use
const
STDIN
;
use
function
array_keys
;
use
function
assert
;
use
function
class_exists
;
use
function
copy
;
use
function
explode
;
use
function
extension_loaded
;
use
function
fgets
;
use
function
file_get_contents
;
use
function
file_put_contents
;
use
function
get_class
;
use
function
getcwd
;
use
function
ini_get
;
use
function
ini_set
;
use
function
is_array
;
use
function
is_callable
;
use
function
is_dir
;
use
function
is_file
;
use
function
is_string
;
use
function
printf
;
use
function
realpath
;
use
function
sort
;
use
function
sprintf
;
use
function
stream_resolve_include_path
;
use
function
strpos
;
use
function
trim
;
use
function
version_compare
;
use
PHPUnit\Framework\TestSuite
;
use
PHPUnit\Runner\Extension\PharLoader
;
use
PHPUnit\Runner\StandardTestSuiteLoader
;
use
PHPUnit\Runner\TestSuiteLoader
;
use
PHPUnit\Runner\Version
;
use
PHPUnit\TextUI\CliArguments\Builder
;
use
PHPUnit\TextUI\CliArguments\Configuration
;
use
PHPUnit\TextUI\CliArguments\Exception
as
ArgumentsException
;
use
PHPUnit\TextUI\CliArguments\Mapper
;
use
PHPUnit\TextUI\XmlConfiguration\CodeCoverage\FilterMapper
;
use
PHPUnit\TextUI\XmlConfiguration\Generator
;
use
PHPUnit\TextUI\XmlConfiguration\Loader
;
use
PHPUnit\TextUI\XmlConfiguration\Migrator
;
use
PHPUnit\TextUI\XmlConfiguration\PhpHandler
;
use
PHPUnit\Util\FileLoader
;
use
PHPUnit\Util\Filesystem
;
use
PHPUnit\Util\Printer
;
use
PHPUnit\Util\TextTestListRenderer
;
use
PHPUnit\Util\Xml\SchemaDetector
;
use
PHPUnit\Util\XmlTestListRenderer
;
use
ReflectionClass
;
use
SebastianBergmann\CodeCoverage\Filter
;
use
SebastianBergmann\CodeCoverage\StaticAnalysis\CacheWarmer
;
use
SebastianBergmann\RecursionContext\InvalidArgumentException
;
use
SebastianBergmann\Timer\Timer
;
use
Throwable
;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*/
class
Command
{
/**
* @var array<string,mixed>
*/
protected
$arguments
=
[];
/**
* @var array<string,mixed>
*/
protected
$longOptions
=
[];
/**
* @var bool
*/
private
$versionStringPrinted
=
false
;
/**
* @psalm-var list<string>
*/
private
$warnings
=
[];
/**
* @throws Exception
*/
public
static
function
main
(
bool
$exit
=
true
):
int
{
try
{
return
(
new
static
)->
run
(
$_SERVER
[
'argv'
],
$exit
);
}
catch
(
Throwable
$t
)
{
throw
new
RuntimeException
(
$t
->
getMessage
(),
(
int
)
$t
->
getCode
(),
$t
,
);
}
}
/**
* @throws Exception
*/
public
function
run
(
array
$argv
,
bool
$exit
=
true
):
int
{
$this
->
handleArguments
(
$argv
);
$runner
=
$this
->
createRunner
();
if
(
$this
->
arguments
[
'test'
]
instanceof
TestSuite
)
{
$suite
=
$this
->
arguments
[
'test'
];
}
else
{
$suite
=
$runner
->
getTest
(
$this
->
arguments
[
'test'
],
$this
->
arguments
[
'testSuffixes'
],
);
}
if
(
$this
->
arguments
[
'listGroups'
])
{
return
$this
->
handleListGroups
(
$suite
,
$exit
);
}
if
(
$this
->
arguments
[
'listSuites'
])
{
return
$this
->
handleListSuites
(
$exit
);
}
if
(
$this
->
arguments
[
'listTests'
])
{
return
$this
->
handleListTests
(
$suite
,
$exit
);
}
if
(
$this
->
arguments
[
'listTestsXml'
])
{
return
$this
->
handleListTestsXml
(
$suite
,
$this
->
arguments
[
'listTestsXml'
],
$exit
);
}
unset
(
$this
->
arguments
[
'test'
],
$this
->
arguments
[
'testFile'
]);
try
{
$result
=
$runner
->
run
(
$suite
,
$this
->
arguments
,
$this
->
warnings
,
$exit
);
}
catch
(
Throwable
$t
)
{
print
$t
->
getMessage
()
.
PHP_EOL
;
}
$return
=
TestRunner
::
FAILURE_EXIT
;
if
(
isset
(
$result
)
&&
$result
->
wasSuccessful
())
{
$return
=
TestRunner
::
SUCCESS_EXIT
;
}
elseif
(!
isset
(
$result
)
||
$result
->
errorCount
()
>
0
)
{
$return
=
TestRunner
::
EXCEPTION_EXIT
;
}
if
(
$exit
)
{
exit
(
$return
);
}
return
$return
;
}
/**
* Create a TestRunner, override in subclasses.
*/
protected
function
createRunner
():
TestRunner
{
return
new
TestRunner
(
$this
->
arguments
[
'loader'
]);
}
/**
* Handles the command-line arguments.
*
* A child class of PHPUnit\TextUI\Command can hook into the argument
* parsing by adding the switch(es) to the $longOptions array and point to a
* callback method that handles the switch(es) in the child class like this
*
* <code>
* <?php
* class MyCommand extends PHPUnit\TextUI\Command
* {
* public function __construct()
* {
* // my-switch won't accept a value, it's an on/off
* $this->longOptions['my-switch'] = 'myHandler';
* // my-secondswitch will accept a value - note the equals sign
* $this->longOptions['my-secondswitch='] = 'myOtherHandler';
* }
*
* // --my-switch -> myHandler()
* protected function myHandler()
* {
* }
*
* // --my-secondswitch foo -> myOtherHandler('foo')
* protected function myOtherHandler ($value)
* {
* }
*
* // You will also need this - the static keyword in the
* // PHPUnit\TextUI\Command will mean that it'll be
* // PHPUnit\TextUI\Command that gets instantiated,
* // not MyCommand
* public static function main($exit = true)
* {
* $command = new static;
*
* return $command->run($_SERVER['argv'], $exit);
* }
*
* }
* </code>
*
* @throws Exception
*/
protected
function
handleArguments
(
array
$argv
):
void
{
try
{
$arguments
=
(
new
Builder
)->
fromParameters
(
$argv
,
array_keys
(
$this
->
longOptions
));
}
catch
(
ArgumentsException
$e
)
{
$this
->
exitWithErrorMessage
(
$e
->
getMessage
());
}
assert
(
isset
(
$arguments
)
&&
$arguments
instanceof
Configuration
);
if
(
$arguments
->
hasGenerateConfiguration
()
&&
$arguments
->
generateConfiguration
())
{
$this
->
generateConfiguration
();
}
if
(
$arguments
->
hasAtLeastVersion
())
{
if
(
version_compare
(
Version
::
id
(),
$arguments
->
atLeastVersion
(),
'>='
))
{
exit
(
TestRunner
::
SUCCESS_EXIT
);
}
exit
(
TestRunner
::
FAILURE_EXIT
);
}
if
(
$arguments
->
hasVersion
()
&&
$arguments
->
version
())
{
$this
->
printVersionString
();
exit
(
TestRunner
::
SUCCESS_EXIT
);
}
if
(
$arguments
->
hasCheckVersion
()
&&
$arguments
->
checkVersion
())
{
$this
->
handleVersionCheck
();
}
if
(
$arguments
->
hasHelp
())
{
$this
->
showHelp
();
exit
(
TestRunner
::
SUCCESS_EXIT
);
}
if
(
$arguments
->
hasUnrecognizedOrderBy
())
{
$this
->
exitWithErrorMessage
(
sprintf
(
'unrecognized --order-by option: %s'
,
$arguments
->
unrecognizedOrderBy
(),
),
);
}
if
(
$arguments
->
hasIniSettings
())
{
foreach
(
$arguments
->
iniSettings
()
as
$name
=>
$value
)
{
ini_set
(
$name
,
$value
);
}
}
if
(
$arguments
->
hasIncludePath
())
{
ini_set
(
'include_path'
,
$arguments
->
includePath
()
.
PATH_SEPARATOR
.
ini_get
(
'include_path'
),
);
}
$this
->
arguments
=
(
new
Mapper
)->
mapToLegacyArray
(
$arguments
);
$this
->
handleCustomOptions
(
$arguments
->
unrecognizedOptions
());
$this
->
handleCustomTestSuite
();
if
(!
isset
(
$this
->
arguments
[
'testSuffixes'
]))
{
$this
->
arguments
[
'testSuffixes'
]
=
[
'Test.php'
,
'.phpt'
];
}
if
(!
isset
(
$this
->
arguments
[
'test'
])
&&
$arguments
->
hasArgument
())
{
$this
->
arguments
[
'test'
]
=
realpath
(
$arguments
->
argument
());
if
(
$this
->
arguments
[
'test'
]
===
false
)
{
$this
->
exitWithErrorMessage
(
sprintf
(
'Cannot open file "%s".'
,
$arguments
->
argument
(),
),
);
}
}
if
(
$this
->
arguments
[
'loader'
]
!==
null
)
{
$this
->
arguments
[
'loader'
]
=
$this
->
handleLoader
(
$this
->
arguments
[
'loader'
]);
}
if
(
isset
(
$this
->
arguments
[
'configuration'
]))
{
if
(
is_dir
(
$this
->
arguments
[
'configuration'
]))
{
$candidate
=
$this
->
configurationFileInDirectory
(
$this
->
arguments
[
'configuration'
]);
if
(
$candidate
!==
null
)
{
$this
->
arguments
[
'configuration'
]
=
$candidate
;
}
}
}
elseif
(
$this
->
arguments
[
'useDefaultConfiguration'
])
{
$candidate
=
$this
->
configurationFileInDirectory
(
getcwd
());
if
(
$candidate
!==
null
)
{
$this
->
arguments
[
'configuration'
]
=
$candidate
;
}
}
if
(
$arguments
->
hasMigrateConfiguration
()
&&
$arguments
->
migrateConfiguration
())
{
if
(!
isset
(
$this
->
arguments
[
'configuration'
]))
{
print
'No configuration file found to migrate.'
.
PHP_EOL
;
exit
(
TestRunner
::
EXCEPTION_EXIT
);
}
$this
->
migrateConfiguration
(
realpath
(
$this
->
arguments
[
'configuration'
]));
}
if
(
isset
(
$this
->
arguments
[
'configuration'
]))
{
try
{
$this
->
arguments
[
'configurationObject'
]
=
(
new
Loader
)->
load
(
$this
->
arguments
[
'configuration'
]);
}
catch
(
Throwable
$e
)
{
print
$e
->
getMessage
()
.
PHP_EOL
;
exit
(
TestRunner
::
FAILURE_EXIT
);
}
$phpunitConfiguration
=
$this
->
arguments
[
'configurationObject'
]->
phpunit
();
(
new
PhpHandler
)->
handle
(
$this
->
arguments
[
'configurationObject'
]->
php
());
if
(
isset
(
$this
->
arguments
[
'bootstrap'
]))
{
$this
->
handleBootstrap
(
$this
->
arguments
[
'bootstrap'
]);
}
elseif
(
$phpunitConfiguration
->
hasBootstrap
())
{
$this
->
handleBootstrap
(
$phpunitConfiguration
->
bootstrap
());
}
if
(!
isset
(
$this
->
arguments
[
'stderr'
]))
{
$this
->
arguments
[
'stderr'
]
=
$phpunitConfiguration
->
stderr
();
}
if
(!
isset
(
$this
->
arguments
[
'noExtensions'
])
&&
$phpunitConfiguration
->
hasExtensionsDirectory
()
&&
extension_loaded
(
'phar'
))
{
$result
=
(
new
PharLoader
)->
loadPharExtensionsInDirectory
(
$phpunitConfiguration
->
extensionsDirectory
());
$this
->
arguments
[
'loadedExtensions'
]
=
$result
[
'loadedExtensions'
];
$this
->
arguments
[
'notLoadedExtensions'
]
=
$result
[
'notLoadedExtensions'
];
unset
(
$result
);
}
if
(!
isset
(
$this
->
arguments
[
'columns'
]))
{
$this
->
arguments
[
'columns'
]
=
$phpunitConfiguration
->
columns
();
}
if
(!
isset
(
$this
->
arguments
[
'printer'
])
&&
$phpunitConfiguration
->
hasPrinterClass
())
{
$file
=
$phpunitConfiguration
->
hasPrinterFile
()
?
$phpunitConfiguration
->
printerFile
()
:
''
;
$this
->
arguments
[
'printer'
]
=
$this
->
handlePrinter
(
$phpunitConfiguration
->
printerClass
(),
$file
,
);
}
if
(
$phpunitConfiguration
->
hasTestSuiteLoaderClass
())
{
$file
=
$phpunitConfiguration
->
hasTestSuiteLoaderFile
()
?
$phpunitConfiguration
->
testSuiteLoaderFile
()
:
''
;
$this
->
arguments
[
'loader'
]
=
$this
->
handleLoader
(
$phpunitConfiguration
->
testSuiteLoaderClass
(),
$file
,
);
}
if
(!
isset
(
$this
->
arguments
[
'testsuite'
])
&&
$phpunitConfiguration
->
hasDefaultTestSuite
())
{
$this
->
arguments
[
'testsuite'
]
=
$phpunitConfiguration
->
defaultTestSuite
();
}
if
(!
isset
(
$this
->
arguments
[
'test'
]))
{
try
{
$this
->
arguments
[
'test'
]
=
(
new
TestSuiteMapper
)->
map
(
$this
->
arguments
[
'configurationObject'
]->
testSuite
(),
$this
->
arguments
[
'testsuite'
]
??
''
,
);
}
catch
(
Exception
$e
)
{
$this
->
printVersionString
();
print
$e
->
getMessage
()
.
PHP_EOL
;
exit
(
TestRunner
::
EXCEPTION_EXIT
);
}
}
}
elseif
(
isset
(
$this
->
arguments
[
'bootstrap'
]))
{
$this
->
handleBootstrap
(
$this
->
arguments
[
'bootstrap'
]);
}
if
(
isset
(
$this
->
arguments
[
'printer'
])
&&
is_string
(
$this
->
arguments
[
'printer'
]))
{
$this
->
arguments
[
'printer'
]
=
$this
->
handlePrinter
(
$this
->
arguments
[
'printer'
]);
}
if
(
isset
(
$this
->
arguments
[
'configurationObject'
],
$this
->
arguments
[
'warmCoverageCache'
]))
{
$this
->
handleWarmCoverageCache
(
$this
->
arguments
[
'configurationObject'
]);
}
if
(!
isset
(
$this
->
arguments
[
'test'
]))
{
$this
->
showHelp
();
exit
(
TestRunner
::
EXCEPTION_EXIT
);
}
}
/**
* Handles the loading of the PHPUnit\Runner\TestSuiteLoader implementation.
*
* @deprecated see https://github.com/sebastianbergmann/phpunit/issues/4039
*/
protected
function
handleLoader
(
string
$loaderClass
,
string
$loaderFile
=
''
):
?
TestSuiteLoader
{
$this
->
warnings
[]
=
'Using a custom test suite loader is deprecated'
;
if
(!
class_exists
(
$loaderClass
,
false
))
{
if
(
$loaderFile
==
''
)
{
$loaderFile
=
Filesystem
::
classNameToFilename
(
$loaderClass
,
);
}
$loaderFile
=
stream_resolve_include_path
(
$loaderFile
);
if
(
$loaderFile
)
{
/**
* @noinspection PhpIncludeInspection
*
* @psalm-suppress UnresolvableInclude
*/
require
$loaderFile
;
}
}
if
(
class_exists
(
$loaderClass
,
false
))
{
try
{
$class
=
new
ReflectionClass
(
$loaderClass
);
// @codeCoverageIgnoreStart
}
catch
(
\ReflectionException
$e
)
{
throw
new
ReflectionException
(
$e
->
getMessage
(),
$e
->
getCode
(),
$e
,
);
}
// @codeCoverageIgnoreEnd
if
(
$class
->
implementsInterface
(
TestSuiteLoader
::
class
)
&&
$class
->
isInstantiable
())
{
$object
=
$class
->
newInstance
();
assert
(
$object
instanceof
TestSuiteLoader
);
return
$object
;
}
}
if
(
$loaderClass
==
StandardTestSuiteLoader
::
class
)
{
return
null
;
}
$this
->
exitWithErrorMessage
(
sprintf
(
'Could not use "%s" as loader.'
,
$loaderClass
,
),
);
return
null
;
}
/**
* Handles the loading of the PHPUnit\Util\Printer implementation.
*
* @return null|Printer|string
*/
protected
function
handlePrinter
(
string
$printerClass
,
string
$printerFile
=
''
)
{
if
(!
class_exists
(
$printerClass
,
false
))
{
if
(
$printerFile
===
''
)
{
$printerFile
=
Filesystem
::
classNameToFilename
(
$printerClass
,
);
}
$printerFile
=
stream_resolve_include_path
(
$printerFile
);
if
(
$printerFile
)
{
/**
* @noinspection PhpIncludeInspection
*
* @psalm-suppress UnresolvableInclude
*/
require
$printerFile
;
}
}
if
(!
class_exists
(
$printerClass
))
{
$this
->
exitWithErrorMessage
(
sprintf
(
'Could not use "%s" as printer: class does not exist'
,
$printerClass
,
),
);
}
try
{
$class
=
new
ReflectionClass
(
$printerClass
);
// @codeCoverageIgnoreStart
}
catch
(
\ReflectionException
$e
)
{
throw
new
ReflectionException
(
$e
->
getMessage
(),
$e
->
getCode
(),
$e
,
);
// @codeCoverageIgnoreEnd
}
if
(!
$class
->
implementsInterface
(
ResultPrinter
::
class
))
{
$this
->
exitWithErrorMessage
(
sprintf
(
'Could not use "%s" as printer: class does not implement %s'
,
$printerClass
,
ResultPrinter
::
class
,
),
);
}
if
(!
$class
->
isInstantiable
())
{
$this
->
exitWithErrorMessage
(
sprintf
(
'Could not use "%s" as printer: class cannot be instantiated'
,
$printerClass
,
),
);
}
if
(
$class
->
isSubclassOf
(
ResultPrinter
::
class
))
{
return
$printerClass
;
}
$outputStream
=
isset
(
$this
->
arguments
[
'stderr'
])
?
'php://stderr'
:
null
;
return
$class
->
newInstance
(
$outputStream
);
}
/**
* Loads a bootstrap file.
*/
protected
function
handleBootstrap
(
string
$filename
):
void
{
try
{
FileLoader
::
checkAndLoad
(
$filename
);
}
catch
(
Throwable
$t
)
{
if
(
$t
instanceof
\PHPUnit\Exception
)
{
$this
->
exitWithErrorMessage
(
$t
->
getMessage
());
}
$message
=
sprintf
(
'Error in bootstrap script: %s:%s%s%s%s'
,
get_class
(
$t
),
PHP_EOL
,
$t
->
getMessage
(),
PHP_EOL
,
$t
->
getTraceAsString
(),
);
while
(
$t
=
$t
->
getPrevious
())
{
$message
.=
sprintf
(
'%s%sPrevious error: %s:%s%s%s%s'
,
PHP_EOL
,
PHP_EOL
,
get_class
(
$t
),
PHP_EOL
,
$t
->
getMessage
(),
PHP_EOL
,
$t
->
getTraceAsString
(),
);
}
$this
->
exitWithErrorMessage
(
$message
);
}
}
protected
function
handleVersionCheck
():
void
{
$this
->
printVersionString
();
$latestVersion
=
file_get_contents
(
'https://phar.phpunit.de/latest-version-of/phpunit'
);
$latestCompatibleVersion
=
file_get_contents
(
'https://phar.phpunit.de/latest-version-of/phpunit-'
.
explode
(
'.'
,
Version
::
series
())[
0
]);
$notLatest
=
version_compare
(
$latestVersion
,
Version
::
id
(),
'>'
);
$notLatestCompatible
=
version_compare
(
$latestCompatibleVersion
,
Version
::
id
(),
'>'
);
if
(
$notLatest
||
$notLatestCompatible
)
{
print
'You are not using the latest version of PHPUnit.'
.
PHP_EOL
;
}
else
{
print
'You are using the latest version of PHPUnit.'
.
PHP_EOL
;
}
if
(
$notLatestCompatible
)
{
printf
(
'The latest version compatible with PHPUnit %s is PHPUnit %s.'
.
PHP_EOL
,
Version
::
id
(),
$latestCompatibleVersion
,
);
}
if
(
$notLatest
)
{
printf
(
'The latest version is PHPUnit %s.'
.
PHP_EOL
,
$latestVersion
,
);
}
exit
(
TestRunner
::
SUCCESS_EXIT
);
}
/**
* Show the help message.
*/
protected
function
showHelp
():
void
{
$this
->
printVersionString
();
(
new
Help
)->
writeToConsole
();
}
/**
* Custom callback for test suite discovery.
*/
protected
function
handleCustomTestSuite
():
void
{
}
private
function
printVersionString
():
void
{
if
(
$this
->
versionStringPrinted
)
{
return
;
}
print
Version
::
getVersionString
()
.
PHP_EOL
.
PHP_EOL
;
$this
->
versionStringPrinted
=
true
;
}
private
function
exitWithErrorMessage
(
string
$message
):
void
{
$this
->
printVersionString
();
print
$message
.
PHP_EOL
;
exit
(
TestRunner
::
FAILURE_EXIT
);
}
private
function
handleListGroups
(
TestSuite
$suite
,
bool
$exit
):
int
{
$this
->
printVersionString
();
$this
->
warnAboutConflictingOptions
(
'listGroups'
,
[
'filter'
,
'groups'
,
'excludeGroups'
,
'testsuite'
,
],
);
print
'Available test group(s):'
.
PHP_EOL
;
$groups
=
$suite
->
getGroups
();
sort
(
$groups
);
foreach
(
$groups
as
$group
)
{
if
(
strpos
(
$group
,
'__phpunit_'
)
===
0
)
{
continue
;
}
printf
(
' - %s'
.
PHP_EOL
,
$group
,
);
}
if
(
$exit
)
{
exit
(
TestRunner
::
SUCCESS_EXIT
);
}
return
TestRunner
::
SUCCESS_EXIT
;
}
/**
* @throws \PHPUnit\Framework\Exception
* @throws XmlConfiguration\Exception
*/
private
function
handleListSuites
(
bool
$exit
):
int
{
$this
->
printVersionString
();
$this
->
warnAboutConflictingOptions
(
'listSuites'
,
[
'filter'
,
'groups'
,
'excludeGroups'
,
'testsuite'
,
],
);
print
'Available test suite(s):'
.
PHP_EOL
;
foreach
(
$this
->
arguments
[
'configurationObject'
]->
testSuite
()
as
$testSuite
)
{
printf
(
' - %s'
.
PHP_EOL
,
$testSuite
->
name
(),
);
}
if
(
$exit
)
{
exit
(
TestRunner
::
SUCCESS_EXIT
);
}
return
TestRunner
::
SUCCESS_EXIT
;
}
/**
* @throws InvalidArgumentException
*/
private
function
handleListTests
(
TestSuite
$suite
,
bool
$exit
):
int
{
$this
->
printVersionString
();
$this
->
warnAboutConflictingOptions
(
'listTests'
,
[
'filter'
,
'groups'
,
'excludeGroups'
,
],
);
$renderer
=
new
TextTestListRenderer
;
print
$renderer
->
render
(
$suite
);
if
(
$exit
)
{
exit
(
TestRunner
::
SUCCESS_EXIT
);
}
return
TestRunner
::
SUCCESS_EXIT
;
}
/**
* @throws InvalidArgumentException
*/
private
function
handleListTestsXml
(
TestSuite
$suite
,
string
$target
,
bool
$exit
):
int
{
$this
->
printVersionString
();
$this
->
warnAboutConflictingOptions
(
'listTestsXml'
,
[
'filter'
,
'groups'
,
'excludeGroups'
,
],
);
$renderer
=
new
XmlTestListRenderer
;
file_put_contents
(
$target
,
$renderer
->
render
(
$suite
));
printf
(
'Wrote list of tests that would have been run to %s'
.
PHP_EOL
,
$target
,
);
if
(
$exit
)
{
exit
(
TestRunner
::
SUCCESS_EXIT
);
}
return
TestRunner
::
SUCCESS_EXIT
;
}
private
function
generateConfiguration
():
void
{
$this
->
printVersionString
();
print
'Generating phpunit.xml in '
.
getcwd
()
.
PHP_EOL
.
PHP_EOL
;
print
'Bootstrap script (relative to path shown above; default: vendor/autoload.php): '
;
$bootstrapScript
=
trim
(
fgets
(
STDIN
));
print
'Tests directory (relative to path shown above; default: tests): '
;
$testsDirectory
=
trim
(
fgets
(
STDIN
));
print
'Source directory (relative to path shown above; default: src): '
;
$src
=
trim
(
fgets
(
STDIN
));
print
'Cache directory (relative to path shown above; default: .phpunit.cache): '
;
$cacheDirectory
=
trim
(
fgets
(
STDIN
));
if
(
$bootstrapScript
===
''
)
{
$bootstrapScript
=
'vendor/autoload.php'
;
}
if
(
$testsDirectory
===
''
)
{
$testsDirectory
=
'tests'
;
}
if
(
$src
===
''
)
{
$src
=
'src'
;
}
if
(
$cacheDirectory
===
''
)
{
$cacheDirectory
=
'.phpunit.cache'
;
}
$generator
=
new
Generator
;
file_put_contents
(
'phpunit.xml'
,
$generator
->
generateDefaultConfiguration
(
Version
::
series
(),
$bootstrapScript
,
$testsDirectory
,
$src
,
$cacheDirectory
,
),
);
print
PHP_EOL
.
'Generated phpunit.xml in '
.
getcwd
()
.
'.'
.
PHP_EOL
;
print
'Make sure to exclude the '
.
$cacheDirectory
.
' directory from version control.'
.
PHP_EOL
;
exit
(
TestRunner
::
SUCCESS_EXIT
);
}
private
function
migrateConfiguration
(
string
$filename
):
void
{
$this
->
printVersionString
();
$result
=
(
new
SchemaDetector
)->
detect
(
$filename
);
if
(!
$result
->
detected
())
{
print
$filename
.
' does not validate against any known schema.'
.
PHP_EOL
;
exit
(
TestRunner
::
EXCEPTION_EXIT
);
}
/** @psalm-suppress MissingThrowsDocblock */
if
(
$result
->
version
()
===
Version
::
series
())
{
print
$filename
.
' does not need to be migrated.'
.
PHP_EOL
;
exit
(
TestRunner
::
EXCEPTION_EXIT
);
}
copy
(
$filename
,
$filename
.
'.bak'
);
print
'Created backup: '
.
$filename
.
'.bak'
.
PHP_EOL
;
try
{
file_put_contents
(
$filename
,
(
new
Migrator
)->
migrate
(
$filename
),
);
print
'Migrated configuration: '
.
$filename
.
PHP_EOL
;
}
catch
(
Throwable
$t
)
{
print
'Migration failed: '
.
$t
->
getMessage
()
.
PHP_EOL
;
exit
(
TestRunner
::
EXCEPTION_EXIT
);
}
exit
(
TestRunner
::
SUCCESS_EXIT
);
}
private
function
handleCustomOptions
(
array
$unrecognizedOptions
):
void
{
foreach
(
$unrecognizedOptions
as
$name
=>
$value
)
{
if
(
isset
(
$this
->
longOptions
[
$name
]))
{
$handler
=
$this
->
longOptions
[
$name
];
}
$name
.=
'='
;
if
(
isset
(
$this
->
longOptions
[
$name
]))
{
$handler
=
$this
->
longOptions
[
$name
];
}
if
(
isset
(
$handler
)
&&
is_callable
([
$this
,
$handler
]))
{
$this
->{
$handler
}(
$value
);
unset
(
$handler
);
}
}
}
private
function
handleWarmCoverageCache
(
XmlConfiguration\Configuration
$configuration
):
void
{
$this
->
printVersionString
();
if
(
isset
(
$this
->
arguments
[
'coverageCacheDirectory'
]))
{
$cacheDirectory
=
$this
->
arguments
[
'coverageCacheDirectory'
];
}
elseif
(
$configuration
->
codeCoverage
()->
hasCacheDirectory
())
{
$cacheDirectory
=
$configuration
->
codeCoverage
()->
cacheDirectory
()->
path
();
}
else
{
print
'Cache for static analysis has not been configured'
.
PHP_EOL
;
exit
(
TestRunner
::
EXCEPTION_EXIT
);
}
$filter
=
new
Filter
;
if
(
$configuration
->
codeCoverage
()->
hasNonEmptyListOfFilesToBeIncludedInCodeCoverageReport
())
{
(
new
FilterMapper
)->
map
(
$filter
,
$configuration
->
codeCoverage
(),
);
}
elseif
(
isset
(
$this
->
arguments
[
'coverageFilter'
]))
{
if
(!
is_array
(
$this
->
arguments
[
'coverageFilter'
]))
{
$coverageFilterDirectories
=
[
$this
->
arguments
[
'coverageFilter'
]];
}
else
{
$coverageFilterDirectories
=
$this
->
arguments
[
'coverageFilter'
];
}
foreach
(
$coverageFilterDirectories
as
$coverageFilterDirectory
)
{
$filter
->
includeDirectory
(
$coverageFilterDirectory
);
}
}
else
{
print
'Filter for code coverage has not been configured'
.
PHP_EOL
;
exit
(
TestRunner
::
EXCEPTION_EXIT
);
}
$timer
=
new
Timer
;
$timer
->
start
();
print
'Warming cache for static analysis ... '
;
(
new
CacheWarmer
)->
warmCache
(
$cacheDirectory
,
!
$configuration
->
codeCoverage
()->
disableCodeCoverageIgnore
(),
$configuration
->
codeCoverage
()->
ignoreDeprecatedCodeUnits
(),
$filter
,
);
print
'done ['
.
$timer
->
stop
()->
asString
()
.
']'
.
PHP_EOL
;
exit
(
TestRunner
::
SUCCESS_EXIT
);
}
private
function
configurationFileInDirectory
(
string
$directory
):
?
string
{
$candidates
=
[
$directory
.
'/phpunit.xml'
,
$directory
.
'/phpunit.xml.dist'
,
];
foreach
(
$candidates
as
$candidate
)
{
if
(
is_file
(
$candidate
))
{
return
realpath
(
$candidate
);
}
}
return
null
;
}
/**
* @psalm-param "listGroups"|"listSuites"|"listTests"|"listTestsXml"|"filter"|"groups"|"excludeGroups"|"testsuite" $key
* @psalm-param list<"listGroups"|"listSuites"|"listTests"|"listTestsXml"|"filter"|"groups"|"excludeGroups"|"testsuite"> $keys
*/
private
function
warnAboutConflictingOptions
(
string
$key
,
array
$keys
):
void
{
$warningPrinted
=
false
;
foreach
(
$keys
as
$_key
)
{
if
(!
empty
(
$this
->
arguments
[
$_key
]))
{
printf
(
'The %s and %s options cannot be combined, %s is ignored'
.
PHP_EOL
,
$this
->
mapKeyToOptionForWarning
(
$_key
),
$this
->
mapKeyToOptionForWarning
(
$key
),
$this
->
mapKeyToOptionForWarning
(
$_key
),
);
$warningPrinted
=
true
;
}
}
if
(
$warningPrinted
)
{
print
PHP_EOL
;
}
}
/**
* @psalm-param "listGroups"|"listSuites"|"listTests"|"listTestsXml"|"filter"|"groups"|"excludeGroups"|"testsuite" $key
*/
private
function
mapKeyToOptionForWarning
(
string
$key
):
string
{
switch
(
$key
)
{
case
'listGroups'
:
return
'--list-groups'
;
case
'listSuites'
:
return
'--list-suites'
;
case
'listTests'
:
return
'--list-tests'
;
case
'listTestsXml'
:
return
'--list-tests-xml'
;
case
'filter'
:
return
'--filter'
;
case
'groups'
:
return
'--group'
;
case
'excludeGroups'
:
return
'--exclude-group'
;
case
'testsuite'
:
return
'--testsuite'
;
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Aug 20 2026, 12:46 (11 w, 5 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ac/2a/6bdfd9ee62daddeebb8ee855dccc
Default Alt Text
Command.php (30 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment