Mercurial > hg > cmmr2012-drupal-site
comparison core/tests/Drupal/Tests/ComposerIntegrationTest.php @ 0:c75dbcec494b
Initial commit from drush-created site
author | Chris Cannam |
---|---|
date | Thu, 05 Jul 2018 14:24:15 +0000 |
parents | |
children | 12f9dff5fda9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c75dbcec494b |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Tests; | |
4 | |
5 use Composer\Semver\Semver; | |
6 | |
7 /** | |
8 * Tests Composer integration. | |
9 * | |
10 * @group Composer | |
11 */ | |
12 class ComposerIntegrationTest extends UnitTestCase { | |
13 | |
14 /** | |
15 * The minimum PHP version supported by Drupal. | |
16 * | |
17 * @see https://www.drupal.org/docs/8/system-requirements/web-server | |
18 * | |
19 * @todo Remove as part of https://www.drupal.org/node/2908079 | |
20 */ | |
21 const MIN_PHP_VERSION = '5.5.9'; | |
22 | |
23 /** | |
24 * Gets human-readable JSON error messages. | |
25 * | |
26 * @return string[] | |
27 * Keys are JSON_ERROR_* constants. | |
28 */ | |
29 protected function getErrorMessages() { | |
30 $messages = [ | |
31 0 => 'No errors found', | |
32 JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded', | |
33 JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON', | |
34 JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded', | |
35 JSON_ERROR_SYNTAX => 'Syntax error', | |
36 JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded', | |
37 ]; | |
38 | |
39 if (version_compare(phpversion(), '5.5.0', '>=')) { | |
40 $messages[JSON_ERROR_RECURSION] = 'One or more recursive references in the value to be encoded'; | |
41 $messages[JSON_ERROR_INF_OR_NAN] = 'One or more NAN or INF values in the value to be encoded'; | |
42 $messages[JSON_ERROR_UNSUPPORTED_TYPE] = 'A value of a type that cannot be encoded was given'; | |
43 } | |
44 | |
45 return $messages; | |
46 } | |
47 | |
48 /** | |
49 * Gets the paths to the folders that contain the Composer integration. | |
50 * | |
51 * @return string[] | |
52 * The paths. | |
53 */ | |
54 protected function getPaths() { | |
55 return [ | |
56 $this->root, | |
57 $this->root . '/core', | |
58 $this->root . '/core/lib/Drupal/Component/Annotation', | |
59 $this->root . '/core/lib/Drupal/Component/Assertion', | |
60 $this->root . '/core/lib/Drupal/Component/Bridge', | |
61 $this->root . '/core/lib/Drupal/Component/ClassFinder', | |
62 $this->root . '/core/lib/Drupal/Component/Datetime', | |
63 $this->root . '/core/lib/Drupal/Component/DependencyInjection', | |
64 $this->root . '/core/lib/Drupal/Component/Diff', | |
65 $this->root . '/core/lib/Drupal/Component/Discovery', | |
66 $this->root . '/core/lib/Drupal/Component/EventDispatcher', | |
67 $this->root . '/core/lib/Drupal/Component/FileCache', | |
68 $this->root . '/core/lib/Drupal/Component/FileSystem', | |
69 $this->root . '/core/lib/Drupal/Component/Gettext', | |
70 $this->root . '/core/lib/Drupal/Component/Graph', | |
71 $this->root . '/core/lib/Drupal/Component/HttpFoundation', | |
72 $this->root . '/core/lib/Drupal/Component/PhpStorage', | |
73 $this->root . '/core/lib/Drupal/Component/Plugin', | |
74 $this->root . '/core/lib/Drupal/Component/ProxyBuilder', | |
75 $this->root . '/core/lib/Drupal/Component/Render', | |
76 $this->root . '/core/lib/Drupal/Component/Serialization', | |
77 $this->root . '/core/lib/Drupal/Component/Transliteration', | |
78 $this->root . '/core/lib/Drupal/Component/Utility', | |
79 $this->root . '/core/lib/Drupal/Component/Uuid', | |
80 ]; | |
81 } | |
82 | |
83 /** | |
84 * Tests composer.json. | |
85 */ | |
86 public function testComposerJson() { | |
87 foreach ($this->getPaths() as $path) { | |
88 $json = file_get_contents($path . '/composer.json'); | |
89 $result = json_decode($json); | |
90 $this->assertNotNull($result, $this->getErrorMessages()[json_last_error()]); | |
91 } | |
92 } | |
93 | |
94 /** | |
95 * Tests composer.lock content-hash. | |
96 */ | |
97 public function testComposerLockHash() { | |
98 $content_hash = self::getContentHash(file_get_contents($this->root . '/composer.json')); | |
99 $lock = json_decode(file_get_contents($this->root . '/composer.lock'), TRUE); | |
100 $this->assertSame($content_hash, $lock['content-hash']); | |
101 } | |
102 | |
103 /** | |
104 * Tests composer.json versions. | |
105 * | |
106 * @param string $path | |
107 * Path to a composer.json to test. | |
108 * | |
109 * @dataProvider providerTestComposerJson | |
110 */ | |
111 public function testComposerTilde($path) { | |
112 $content = json_decode(file_get_contents($path), TRUE); | |
113 $composer_keys = array_intersect(['require', 'require-dev'], array_keys($content)); | |
114 if (empty($composer_keys)) { | |
115 $this->markTestSkipped("$path has no keys to test"); | |
116 } | |
117 foreach ($composer_keys as $composer_key) { | |
118 foreach ($content[$composer_key] as $dependency => $version) { | |
119 // We allow tildes if the dependency is a Symfony component. | |
120 // @see https://www.drupal.org/node/2887000 | |
121 if (strpos($dependency, 'symfony/') === 0) { | |
122 continue; | |
123 } | |
124 $this->assertFalse(strpos($version, '~'), "Dependency $dependency in $path contains a tilde, use a caret."); | |
125 } | |
126 } | |
127 } | |
128 | |
129 /** | |
130 * Data provider for all the composer.json provided by Drupal core. | |
131 * | |
132 * @return array | |
133 */ | |
134 public function providerTestComposerJson() { | |
135 $root = realpath(__DIR__ . '/../../../../'); | |
136 $tests = [[$root . '/composer.json']]; | |
137 $directory = new \RecursiveDirectoryIterator($root . '/core'); | |
138 $iterator = new \RecursiveIteratorIterator($directory); | |
139 /** @var \SplFileInfo $file */ | |
140 foreach ($iterator as $file) { | |
141 if ($file->getFilename() === 'composer.json' && strpos($file->getPath(), 'core/modules/system/tests/fixtures/HtaccessTest') === FALSE) { | |
142 $tests[] = [$file->getRealPath()]; | |
143 } | |
144 } | |
145 return $tests; | |
146 } | |
147 | |
148 /** | |
149 * Tests core's composer.json replace section. | |
150 * | |
151 * Verify that all core modules are also listed in the 'replace' section of | |
152 * core's composer.json. | |
153 */ | |
154 public function testAllModulesReplaced() { | |
155 // Assemble a path to core modules. | |
156 $module_path = $this->root . '/core/modules'; | |
157 | |
158 // Grab the 'replace' section of the core composer.json file. | |
159 $json = json_decode(file_get_contents($this->root . '/core/composer.json')); | |
160 $composer_replace_packages = (array) $json->replace; | |
161 | |
162 // Get a list of all the files in the module path. | |
163 $folders = scandir($module_path); | |
164 | |
165 // Make sure we only deal with directories that aren't . or .. | |
166 $module_names = []; | |
167 $discard = ['.', '..']; | |
168 foreach ($folders as $file_name) { | |
169 if ((!in_array($file_name, $discard)) && is_dir($module_path . '/' . $file_name)) { | |
170 $module_names[] = $file_name; | |
171 } | |
172 } | |
173 | |
174 // Assert that each core module has a corresponding 'replace' in | |
175 // composer.json. | |
176 foreach ($module_names as $module_name) { | |
177 $this->assertArrayHasKey( | |
178 'drupal/' . $module_name, | |
179 $composer_replace_packages, | |
180 'Unable to find ' . $module_name . ' in replace list of composer.json' | |
181 ); | |
182 } | |
183 } | |
184 | |
185 /** | |
186 * Tests package requirements for the minimum supported PHP version by Drupal. | |
187 * | |
188 * @todo This can be removed when DrupalCI supports dependency regression | |
189 * testing in https://www.drupal.org/node/2874198 | |
190 */ | |
191 public function testMinPHPVersion() { | |
192 // Check for lockfile in the application root. If the lockfile does not | |
193 // exist, then skip this test. | |
194 $lockfile = $this->root . '/composer.lock'; | |
195 if (!file_exists($lockfile)) { | |
196 $this->markTestSkipped('/composer.lock is not available.'); | |
197 } | |
198 | |
199 $lock = json_decode(file_get_contents($lockfile), TRUE); | |
200 | |
201 // Check the PHP version for each installed non-development package. The | |
202 // testing infrastructure uses the uses the development packages, and may | |
203 // update them for particular environment configurations. In particular, | |
204 // PHP 7.2+ require an updated version of phpunit, which is incompatible | |
205 // with Drupal's minimum PHP requirement. | |
206 foreach ($lock['packages'] as $package) { | |
207 if (isset($package['require']['php'])) { | |
208 $this->assertTrue(Semver::satisfies(static::MIN_PHP_VERSION, $package['require']['php']), $package['name'] . ' has a PHP dependency requirement of "' . $package['require']['php'] . '"'); | |
209 } | |
210 } | |
211 } | |
212 | |
213 // @codingStandardsIgnoreStart | |
214 /** | |
215 * The following method is copied from \Composer\Package\Locker. | |
216 * | |
217 * @see https://github.com/composer/composer | |
218 */ | |
219 /** | |
220 * Returns the md5 hash of the sorted content of the composer file. | |
221 * | |
222 * @param string $composerFileContents The contents of the composer file. | |
223 * | |
224 * @return string | |
225 */ | |
226 protected static function getContentHash($composerFileContents) | |
227 { | |
228 $content = json_decode($composerFileContents, true); | |
229 | |
230 $relevantKeys = array( | |
231 'name', | |
232 'version', | |
233 'require', | |
234 'require-dev', | |
235 'conflict', | |
236 'replace', | |
237 'provide', | |
238 'minimum-stability', | |
239 'prefer-stable', | |
240 'repositories', | |
241 'extra', | |
242 ); | |
243 | |
244 $relevantContent = array(); | |
245 | |
246 foreach (array_intersect($relevantKeys, array_keys($content)) as $key) { | |
247 $relevantContent[$key] = $content[$key]; | |
248 } | |
249 if (isset($content['config']['platform'])) { | |
250 $relevantContent['config']['platform'] = $content['config']['platform']; | |
251 } | |
252 | |
253 ksort($relevantContent); | |
254 | |
255 return md5(json_encode($relevantContent)); | |
256 } | |
257 // @codingStandardsIgnoreEnd | |
258 | |
259 } |