2015-08-18 00:00:26 +00:00
< ? php
/**
* @ file
* Autoloader for Drupal PHPUnit testing .
*
* @ see phpunit . xml . dist
*/
2016-05-04 21:35:41 +00:00
use Drupal\Component\Assertion\Handle ;
2018-11-23 12:29:20 +00:00
use Drupal\Core\Composer\Composer ;
use PHPUnit\Runner\Version ;
2016-05-04 21:35:41 +00:00
2015-08-18 00:00:26 +00:00
/**
* Finds all valid extension directories recursively within a given directory .
*
* @ param string $scan_directory
* The directory that should be recursively scanned .
* @ return array
* An associative array of extension directories found within the scanned
* directory , keyed by extension name .
*/
function drupal_phpunit_find_extension_directories ( $scan_directory ) {
2017-04-13 14:53:35 +00:00
$extensions = [];
2015-08-18 00:00:26 +00:00
$dirs = new \RecursiveIteratorIterator ( new \RecursiveDirectoryIterator ( $scan_directory , \RecursiveDirectoryIterator :: FOLLOW_SYMLINKS ));
foreach ( $dirs as $dir ) {
2015-09-04 20:20:09 +00:00
if ( strpos ( $dir -> getPathname (), '.info.yml' ) !== FALSE ) {
2016-07-07 16:44:38 +00:00
// Cut off ".info.yml" from the filename for use as the extension name. We
// use getRealPath() so that we can scan extensions represented by
// directory aliases.
2015-09-04 20:20:09 +00:00
$extensions [ substr ( $dir -> getFilename (), 0 , - 9 )] = $dir -> getPathInfo ()
-> getRealPath ();
2015-08-18 00:00:26 +00:00
}
}
return $extensions ;
}
/**
* Returns directories under which contributed extensions may exist .
*
2016-07-07 16:44:38 +00:00
* @ param string $root
* ( optional ) Path to the root of the Drupal installation .
*
2015-08-18 00:00:26 +00:00
* @ return array
* An array of directories under which contributed extensions may exist .
*/
2016-07-07 16:44:38 +00:00
function drupal_phpunit_contrib_extension_directory_roots ( $root = NULL ) {
if ( $root === NULL ) {
$root = dirname ( dirname ( __DIR__ ));
}
2017-04-13 14:53:35 +00:00
$paths = [
2015-09-04 20:20:09 +00:00
$root . '/core/modules' ,
$root . '/core/profiles' ,
$root . '/modules' ,
$root . '/profiles' ,
2016-09-07 20:26:21 +00:00
$root . '/themes' ,
2017-04-13 14:53:35 +00:00
];
2015-09-04 20:20:09 +00:00
$sites_path = $root . '/sites' ;
2015-08-18 00:00:26 +00:00
// Note this also checks sites/../modules and sites/../profiles.
foreach ( scandir ( $sites_path ) as $site ) {
2015-09-04 20:20:09 +00:00
if ( $site [ 0 ] === '.' || $site === 'simpletest' ) {
continue ;
}
2015-08-18 00:00:26 +00:00
$path = " $sites_path / $site " ;
$paths [] = is_dir ( " $path /modules " ) ? realpath ( " $path /modules " ) : NULL ;
$paths [] = is_dir ( " $path /profiles " ) ? realpath ( " $path /profiles " ) : NULL ;
2016-09-07 20:26:21 +00:00
$paths [] = is_dir ( " $path /themes " ) ? realpath ( " $path /themes " ) : NULL ;
2015-08-18 00:00:26 +00:00
}
2018-11-23 12:29:20 +00:00
return array_filter ( $paths , 'file_exists' );
2015-08-18 00:00:26 +00:00
}
/**
* Registers the namespace for each extension directory with the autoloader .
*
* @ param array $dirs
* An associative array of extension directories , keyed by extension name .
2015-09-04 20:20:09 +00:00
*
* @ return array
* An associative array of extension directories , keyed by their namespace .
2015-08-18 00:00:26 +00:00
*/
2015-09-04 20:20:09 +00:00
function drupal_phpunit_get_extension_namespaces ( $dirs ) {
2017-04-13 14:53:35 +00:00
$suite_names = [ 'Unit' , 'Kernel' , 'Functional' , 'FunctionalJavascript' ];
$namespaces = [];
2015-08-18 00:00:26 +00:00
foreach ( $dirs as $extension => $dir ) {
if ( is_dir ( $dir . '/src' )) {
// Register the PSR-4 directory for module-provided classes.
2015-09-04 20:20:09 +00:00
$namespaces [ 'Drupal\\' . $extension . '\\' ][] = $dir . '/src' ;
2015-08-18 00:00:26 +00:00
}
2017-04-13 14:53:35 +00:00
$test_dir = $dir . '/tests/src' ;
if ( is_dir ( $test_dir )) {
foreach ( $suite_names as $suite_name ) {
$suite_dir = $test_dir . '/' . $suite_name ;
if ( is_dir ( $suite_dir )) {
// Register the PSR-4 directory for PHPUnit-based suites.
$namespaces [ 'Drupal\\Tests\\' . $extension . '\\' . $suite_name . '\\' ][] = $suite_dir ;
}
}
// Extensions can have a \Drupal\extension\Traits namespace for
// cross-suite trait code.
$trait_dir = $test_dir . '/Traits' ;
if ( is_dir ( $trait_dir )) {
$namespaces [ 'Drupal\\Tests\\' . $extension . '\\Traits\\' ][] = $trait_dir ;
}
2015-08-18 00:00:26 +00:00
}
}
2015-09-04 20:20:09 +00:00
return $namespaces ;
2015-08-18 00:00:26 +00:00
}
2015-11-04 19:11:27 +00:00
// We define the COMPOSER_INSTALL constant, so that PHPUnit knows where to
// autoload from. This is needed for tests run in isolation mode, because
// phpunit.xml.dist is located in a non-default directory relative to the
// PHPUnit executable.
if ( ! defined ( 'PHPUNIT_COMPOSER_INSTALL' )) {
define ( 'PHPUNIT_COMPOSER_INSTALL' , __DIR__ . '/../../autoload.php' );
}
2016-01-07 00:31:26 +00:00
/**
* Populate class loader with additional namespaces for tests .
*
* We run this in a function to avoid setting the class loader to a global
* that can change . This change can cause unpredictable false positives for
* phpunit ' s global state change watcher . The class loader can be retrieved from
* composer at any time by requiring autoload . php .
*/
function drupal_phpunit_populate_class_loader () {
/** @var \Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__ . '/../../autoload.php' ;
// Start with classes in known locations.
$loader -> add ( 'Drupal\\Tests' , __DIR__ );
2018-11-23 12:29:20 +00:00
$loader -> add ( 'Drupal\\TestSite' , __DIR__ );
2016-01-07 00:31:26 +00:00
$loader -> add ( 'Drupal\\KernelTests' , __DIR__ );
2016-04-20 16:56:34 +00:00
$loader -> add ( 'Drupal\\FunctionalTests' , __DIR__ );
$loader -> add ( 'Drupal\\FunctionalJavascriptTests' , __DIR__ );
2016-01-07 00:31:26 +00:00
if ( ! isset ( $GLOBALS [ 'namespaces' ])) {
// Scan for arbitrary extension namespaces from core and contrib.
$extension_roots = drupal_phpunit_contrib_extension_directory_roots ();
$dirs = array_map ( 'drupal_phpunit_find_extension_directories' , $extension_roots );
2017-04-13 14:53:35 +00:00
$dirs = array_reduce ( $dirs , 'array_merge' , []);
2016-01-07 00:31:26 +00:00
$GLOBALS [ 'namespaces' ] = drupal_phpunit_get_extension_namespaces ( $dirs );
}
foreach ( $GLOBALS [ 'namespaces' ] as $prefix => $paths ) {
$loader -> addPsr4 ( $prefix , $paths );
}
return $loader ;
};
// Do class loader population.
drupal_phpunit_populate_class_loader ();
2015-08-18 00:00:26 +00:00
2018-11-23 12:29:20 +00:00
// Ensure we have the correct PHPUnit version for the version of PHP.
if ( class_exists ( '\PHPUnit_Runner_Version' )) {
$phpunit_version = \PHPUnit_Runner_Version :: id ();
}
else {
$phpunit_version = Version :: id ();
}
if ( ! Composer :: upgradePHPUnitCheck ( $phpunit_version )) {
$message = " PHPUnit testing framework version 6 or greater is required when running on PHP 7.0 or greater. Run the command 'composer run-script drupal-phpunit-upgrade' in order to fix this. " ;
echo " \033 [31m " . $message . " \n \033 [0m " ;
exit ( 1 );
}
2015-08-18 00:00:26 +00:00
// Set sane locale settings, to ensure consistent string, dates, times and
// numbers handling.
// @see \Drupal\Core\DrupalKernel::bootEnvironment()
setlocale ( LC_ALL , 'C' );
2018-11-23 12:29:20 +00:00
// Set appropriate configuration for multi-byte strings.
mb_internal_encoding ( 'utf-8' );
mb_language ( 'uni' );
2015-08-18 00:00:26 +00:00
// Set the default timezone. While this doesn't cause any tests to fail, PHP
2015-09-04 20:20:09 +00:00
// complains if 'date.timezone' is not set in php.ini. The Australia/Sydney
// timezone is chosen so all tests are run using an edge case scenario (UTC+10
// and DST). This choice is made to prevent timezone related regressions and
// reduce the fragility of the testing system in general.
date_default_timezone_set ( 'Australia/Sydney' );
// Runtime assertions. PHPUnit follows the php.ini assert.active setting for
// runtime assertions. By default this setting is on. Here we make a call to
// make PHP 5 and 7 handle assertion failures the same way, but this call does
// not turn runtime assertions on if they weren't on already.
2016-05-04 21:35:41 +00:00
Handle :: register ();
2018-11-23 12:29:20 +00:00
// PHPUnit 4 to PHPUnit 6 bridge. Tests written for PHPUnit 4 need to work on
// PHPUnit 6 with a minimum of fuss.
if ( version_compare ( $phpunit_version , '6.1' , '>=' )) {
class_alias ( '\PHPUnit\Framework\AssertionFailedError' , '\PHPUnit_Framework_AssertionFailedError' );
class_alias ( '\PHPUnit\Framework\Constraint\Count' , '\PHPUnit_Framework_Constraint_Count' );
class_alias ( '\PHPUnit\Framework\Error\Error' , '\PHPUnit_Framework_Error' );
class_alias ( '\PHPUnit\Framework\Error\Warning' , '\PHPUnit_Framework_Error_Warning' );
class_alias ( '\PHPUnit\Framework\ExpectationFailedException' , '\PHPUnit_Framework_ExpectationFailedException' );
class_alias ( '\PHPUnit\Framework\Exception' , '\PHPUnit_Framework_Exception' );
class_alias ( '\PHPUnit\Framework\MockObject\Matcher\InvokedRecorder' , '\PHPUnit_Framework_MockObject_Matcher_InvokedRecorder' );
class_alias ( '\PHPUnit\Framework\SkippedTestError' , '\PHPUnit_Framework_SkippedTestError' );
class_alias ( '\PHPUnit\Framework\TestCase' , '\PHPUnit_Framework_TestCase' );
class_alias ( '\PHPUnit\Util\Test' , '\PHPUnit_Util_Test' );
class_alias ( '\PHPUnit\Util\Xml' , '\PHPUnit_Util_XML' );
}