Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /**
|
Chris@0
|
4 * @file
|
Chris@0
|
5 * Autoloader for Drupal PHPUnit testing.
|
Chris@0
|
6 *
|
Chris@0
|
7 * @see phpunit.xml.dist
|
Chris@0
|
8 */
|
Chris@0
|
9
|
Chris@0
|
10 use Drupal\Component\Assertion\Handle;
|
Chris@0
|
11
|
Chris@0
|
12 /**
|
Chris@0
|
13 * Finds all valid extension directories recursively within a given directory.
|
Chris@0
|
14 *
|
Chris@0
|
15 * @param string $scan_directory
|
Chris@0
|
16 * The directory that should be recursively scanned.
|
Chris@0
|
17 * @return array
|
Chris@0
|
18 * An associative array of extension directories found within the scanned
|
Chris@0
|
19 * directory, keyed by extension name.
|
Chris@0
|
20 */
|
Chris@0
|
21 function drupal_phpunit_find_extension_directories($scan_directory) {
|
Chris@0
|
22 $extensions = [];
|
Chris@0
|
23 $dirs = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($scan_directory, \RecursiveDirectoryIterator::FOLLOW_SYMLINKS));
|
Chris@0
|
24 foreach ($dirs as $dir) {
|
Chris@0
|
25 if (strpos($dir->getPathname(), '.info.yml') !== FALSE) {
|
Chris@0
|
26 // Cut off ".info.yml" from the filename for use as the extension name. We
|
Chris@0
|
27 // use getRealPath() so that we can scan extensions represented by
|
Chris@0
|
28 // directory aliases.
|
Chris@0
|
29 $extensions[substr($dir->getFilename(), 0, -9)] = $dir->getPathInfo()
|
Chris@0
|
30 ->getRealPath();
|
Chris@0
|
31 }
|
Chris@0
|
32 }
|
Chris@0
|
33 return $extensions;
|
Chris@0
|
34 }
|
Chris@0
|
35
|
Chris@0
|
36 /**
|
Chris@0
|
37 * Returns directories under which contributed extensions may exist.
|
Chris@0
|
38 *
|
Chris@0
|
39 * @param string $root
|
Chris@0
|
40 * (optional) Path to the root of the Drupal installation.
|
Chris@0
|
41 *
|
Chris@0
|
42 * @return array
|
Chris@0
|
43 * An array of directories under which contributed extensions may exist.
|
Chris@0
|
44 */
|
Chris@0
|
45 function drupal_phpunit_contrib_extension_directory_roots($root = NULL) {
|
Chris@0
|
46 if ($root === NULL) {
|
Chris@0
|
47 $root = dirname(dirname(__DIR__));
|
Chris@0
|
48 }
|
Chris@0
|
49 $paths = [
|
Chris@0
|
50 $root . '/core/modules',
|
Chris@0
|
51 $root . '/core/profiles',
|
Chris@0
|
52 $root . '/modules',
|
Chris@0
|
53 $root . '/profiles',
|
Chris@0
|
54 $root . '/themes',
|
Chris@0
|
55 ];
|
Chris@0
|
56 $sites_path = $root . '/sites';
|
Chris@0
|
57 // Note this also checks sites/../modules and sites/../profiles.
|
Chris@0
|
58 foreach (scandir($sites_path) as $site) {
|
Chris@0
|
59 if ($site[0] === '.' || $site === 'simpletest') {
|
Chris@0
|
60 continue;
|
Chris@0
|
61 }
|
Chris@0
|
62 $path = "$sites_path/$site";
|
Chris@0
|
63 $paths[] = is_dir("$path/modules") ? realpath("$path/modules") : NULL;
|
Chris@0
|
64 $paths[] = is_dir("$path/profiles") ? realpath("$path/profiles") : NULL;
|
Chris@0
|
65 $paths[] = is_dir("$path/themes") ? realpath("$path/themes") : NULL;
|
Chris@0
|
66 }
|
Chris@0
|
67 return array_filter($paths);
|
Chris@0
|
68 }
|
Chris@0
|
69
|
Chris@0
|
70 /**
|
Chris@0
|
71 * Registers the namespace for each extension directory with the autoloader.
|
Chris@0
|
72 *
|
Chris@0
|
73 * @param array $dirs
|
Chris@0
|
74 * An associative array of extension directories, keyed by extension name.
|
Chris@0
|
75 *
|
Chris@0
|
76 * @return array
|
Chris@0
|
77 * An associative array of extension directories, keyed by their namespace.
|
Chris@0
|
78 */
|
Chris@0
|
79 function drupal_phpunit_get_extension_namespaces($dirs) {
|
Chris@0
|
80 $suite_names = ['Unit', 'Kernel', 'Functional', 'FunctionalJavascript'];
|
Chris@0
|
81 $namespaces = [];
|
Chris@0
|
82 foreach ($dirs as $extension => $dir) {
|
Chris@0
|
83 if (is_dir($dir . '/src')) {
|
Chris@0
|
84 // Register the PSR-4 directory for module-provided classes.
|
Chris@0
|
85 $namespaces['Drupal\\' . $extension . '\\'][] = $dir . '/src';
|
Chris@0
|
86 }
|
Chris@0
|
87 $test_dir = $dir . '/tests/src';
|
Chris@0
|
88 if (is_dir($test_dir)) {
|
Chris@0
|
89 foreach ($suite_names as $suite_name) {
|
Chris@0
|
90 $suite_dir = $test_dir . '/' . $suite_name;
|
Chris@0
|
91 if (is_dir($suite_dir)) {
|
Chris@0
|
92 // Register the PSR-4 directory for PHPUnit-based suites.
|
Chris@0
|
93 $namespaces['Drupal\\Tests\\' . $extension . '\\' . $suite_name . '\\'][] = $suite_dir;
|
Chris@0
|
94 }
|
Chris@0
|
95 }
|
Chris@0
|
96 // Extensions can have a \Drupal\extension\Traits namespace for
|
Chris@0
|
97 // cross-suite trait code.
|
Chris@0
|
98 $trait_dir = $test_dir . '/Traits';
|
Chris@0
|
99 if (is_dir($trait_dir)) {
|
Chris@0
|
100 $namespaces['Drupal\\Tests\\' . $extension . '\\Traits\\'][] = $trait_dir;
|
Chris@0
|
101 }
|
Chris@0
|
102 }
|
Chris@0
|
103 }
|
Chris@0
|
104 return $namespaces;
|
Chris@0
|
105 }
|
Chris@0
|
106
|
Chris@0
|
107 // We define the COMPOSER_INSTALL constant, so that PHPUnit knows where to
|
Chris@0
|
108 // autoload from. This is needed for tests run in isolation mode, because
|
Chris@0
|
109 // phpunit.xml.dist is located in a non-default directory relative to the
|
Chris@0
|
110 // PHPUnit executable.
|
Chris@0
|
111 if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
|
Chris@0
|
112 define('PHPUNIT_COMPOSER_INSTALL', __DIR__ . '/../../autoload.php');
|
Chris@0
|
113 }
|
Chris@0
|
114
|
Chris@0
|
115 /**
|
Chris@0
|
116 * Populate class loader with additional namespaces for tests.
|
Chris@0
|
117 *
|
Chris@0
|
118 * We run this in a function to avoid setting the class loader to a global
|
Chris@0
|
119 * that can change. This change can cause unpredictable false positives for
|
Chris@0
|
120 * phpunit's global state change watcher. The class loader can be retrieved from
|
Chris@0
|
121 * composer at any time by requiring autoload.php.
|
Chris@0
|
122 */
|
Chris@0
|
123 function drupal_phpunit_populate_class_loader() {
|
Chris@0
|
124
|
Chris@0
|
125 /** @var \Composer\Autoload\ClassLoader $loader */
|
Chris@0
|
126 $loader = require __DIR__ . '/../../autoload.php';
|
Chris@0
|
127
|
Chris@0
|
128 // Start with classes in known locations.
|
Chris@0
|
129 $loader->add('Drupal\\Tests', __DIR__);
|
Chris@0
|
130 $loader->add('Drupal\\KernelTests', __DIR__);
|
Chris@0
|
131 $loader->add('Drupal\\FunctionalTests', __DIR__);
|
Chris@0
|
132 $loader->add('Drupal\\FunctionalJavascriptTests', __DIR__);
|
Chris@0
|
133
|
Chris@0
|
134 if (!isset($GLOBALS['namespaces'])) {
|
Chris@0
|
135 // Scan for arbitrary extension namespaces from core and contrib.
|
Chris@0
|
136 $extension_roots = drupal_phpunit_contrib_extension_directory_roots();
|
Chris@0
|
137
|
Chris@0
|
138 $dirs = array_map('drupal_phpunit_find_extension_directories', $extension_roots);
|
Chris@0
|
139 $dirs = array_reduce($dirs, 'array_merge', []);
|
Chris@0
|
140 $GLOBALS['namespaces'] = drupal_phpunit_get_extension_namespaces($dirs);
|
Chris@0
|
141 }
|
Chris@0
|
142 foreach ($GLOBALS['namespaces'] as $prefix => $paths) {
|
Chris@0
|
143 $loader->addPsr4($prefix, $paths);
|
Chris@0
|
144 }
|
Chris@0
|
145
|
Chris@0
|
146 return $loader;
|
Chris@0
|
147 };
|
Chris@0
|
148
|
Chris@0
|
149 // Do class loader population.
|
Chris@0
|
150 drupal_phpunit_populate_class_loader();
|
Chris@0
|
151
|
Chris@0
|
152 // Set sane locale settings, to ensure consistent string, dates, times and
|
Chris@0
|
153 // numbers handling.
|
Chris@0
|
154 // @see \Drupal\Core\DrupalKernel::bootEnvironment()
|
Chris@0
|
155 setlocale(LC_ALL, 'C');
|
Chris@0
|
156
|
Chris@0
|
157 // Set the default timezone. While this doesn't cause any tests to fail, PHP
|
Chris@0
|
158 // complains if 'date.timezone' is not set in php.ini. The Australia/Sydney
|
Chris@0
|
159 // timezone is chosen so all tests are run using an edge case scenario (UTC+10
|
Chris@0
|
160 // and DST). This choice is made to prevent timezone related regressions and
|
Chris@0
|
161 // reduce the fragility of the testing system in general.
|
Chris@0
|
162 date_default_timezone_set('Australia/Sydney');
|
Chris@0
|
163
|
Chris@0
|
164 // Runtime assertions. PHPUnit follows the php.ini assert.active setting for
|
Chris@0
|
165 // runtime assertions. By default this setting is on. Here we make a call to
|
Chris@0
|
166 // make PHP 5 and 7 handle assertion failures the same way, but this call does
|
Chris@0
|
167 // not turn runtime assertions on if they weren't on already.
|
Chris@0
|
168 Handle::register();
|