[TASK] Prepare Frontend Tests for additional site handling tests
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / Functional / SiteHandling / AbstractTestCase.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Frontend\Tests\Functional\SiteHandling;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait;
19 use TYPO3\CMS\Core\Utility\ArrayUtility;
20 use TYPO3\CMS\Frontend\Page\CacheHashCalculator;
21 use TYPO3\CMS\Frontend\Tests\Functional\SiteHandling\Fixtures\LinkHandlingController;
22 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\ArrayValueInstruction;
23 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
24
25 /**
26 * Abstract test case for frontend requests
27 */
28 abstract class AbstractTestCase extends FunctionalTestCase
29 {
30 use SiteBasedTestTrait;
31
32 protected const ENCRYPTION_KEY = '4408d27a916d51e624b69af3554f516dbab61037a9f7b9fd6f81b4d3bedeccb6';
33
34 protected const TYPO3_CONF_VARS = [
35 'SYS' => [
36 'encryptionKey' => self::ENCRYPTION_KEY,
37 ],
38 'FE' => [
39 'cacheHash' => [
40 'requireCacheHashPresenceParameters' => ['testing[value]']
41 ],
42 ]
43 ];
44
45 protected const LANGUAGE_PRESETS = [
46 'EN' => ['id' => 0, 'title' => 'English', 'locale' => 'en_US.UTF8', 'iso' => 'en', 'hrefLang' => 'en-US', 'direction' => ''],
47 'FR' => ['id' => 1, 'title' => 'French', 'locale' => 'fr_FR.UTF8', 'iso' => 'fr', 'hrefLang' => 'fr-FR', 'direction' => ''],
48 'FR-CA' => ['id' => 2, 'title' => 'Franco-Canadian', 'locale' => 'fr_CA.UTF8', 'iso' => 'fr', 'hrefLang' => 'fr-CA', 'direction' => ''],
49 ];
50
51 /**
52 * @var string[]
53 */
54 protected $coreExtensionsToLoad = ['frontend', 'workspaces'];
55
56 /**
57 * @var string[]
58 */
59 protected $pathsToLinkInTestInstance = [
60 'typo3/sysext/core/Tests/Functional/Fixtures/Frontend/AdditionalConfiguration.php' => 'typo3conf/AdditionalConfiguration.php',
61 ];
62
63 /**
64 * Combines string values of multiple array as cross-product into flat items.
65 *
66 * Example:
67 * + meltStrings(['a','b'], ['c','e'], ['f','g'])
68 * + results into ['acf', 'acg', 'aef', 'aeg', 'bcf', 'bcg', 'bef', 'beg']
69 *
70 * @param array $arrays Distinct array that should be melted
71 * @param callable $finalCallback Callback being executed on last multiplier
72 * @param string $prefix Prefix containing concatenated previous values
73 * @return array
74 */
75 protected function meltStrings(array $arrays, callable $finalCallback = null, string $prefix = ''): array
76 {
77 $results = [];
78 $array = array_shift($arrays);
79 foreach ($array as $item) {
80 $resultItem = $prefix . $item;
81 if (count($arrays) > 0) {
82 $results = array_merge(
83 $results,
84 $this->meltStrings($arrays, $finalCallback, $resultItem)
85 );
86 continue;
87 }
88 if ($finalCallback !== null) {
89 $resultItem = call_user_func($finalCallback, $resultItem);
90 }
91 $results[] = $resultItem;
92 }
93 return $results;
94 }
95
96 /**
97 * @param array $array
98 * @return array
99 */
100 protected function wrapInArray(array $array): array
101 {
102 return array_map(
103 function ($item) {
104 return [$item];
105 },
106 $array
107 );
108 }
109
110 /**
111 * @param string[] $array
112 * @return array
113 */
114 protected function keysFromValues(array $array): array
115 {
116 return array_combine($array, $array);
117 }
118
119 /**
120 * Generates key names based on a template and array items as arguments.
121 *
122 * + keysFromTemplate([[1, 2, 3], [11, 22, 33]], '%1$d->%2$d (user:%3$d)')
123 * + returns the following array with generated keys
124 * [
125 * '1->2 (user:3)' => [1, 2, 3],
126 * '11->22 (user:33)' => [11, 22, 33],
127 * ]
128 *
129 * @param array $array
130 * @param string $template
131 * @param callable|null $callback
132 * @return array
133 */
134 protected function keysFromTemplate(array $array, string $template, callable $callback = null): array
135 {
136 $keys = array_unique(
137 array_map(
138 function (array $values) use ($template, $callback) {
139 if ($callback !== null) {
140 $values = call_user_func($callback, $values);
141 }
142 return vsprintf($template, $values);
143 },
144 $array
145 )
146 );
147
148 if (count($keys) !== count($array)) {
149 throw new \LogicException(
150 'Amount of generated keys does not match to item count.',
151 1534682840
152 );
153 }
154
155 return array_combine($keys, $array);
156 }
157
158 /**
159 * @param array $items
160 */
161 protected static function failIfArrayIsNotEmpty(array $items): void
162 {
163 if (empty($items)) {
164 return;
165 }
166
167 static::fail(
168 'Array was not empty as expected, but contained these items:' . LF
169 . '* ' . implode(LF . '* ', $items)
170 );
171 }
172
173 /**
174 * @param string $uri
175 * @return string
176 */
177 protected static function generateCacheHash(string $uri): string
178 {
179 if (!isset($GLOBALS['TYPO3_CONF_VARS'])) {
180 $GLOBALS['TYPO3_CONF_VARS'] = [];
181 }
182
183 $configuration = $GLOBALS['TYPO3_CONF_VARS'];
184 ArrayUtility::mergeRecursiveWithOverrule(
185 $GLOBALS['TYPO3_CONF_VARS'],
186 static::TYPO3_CONF_VARS
187 );
188
189 $calculator = new CacheHashCalculator();
190 $parameters = $calculator->getRelevantParameters(
191 parse_url($uri, PHP_URL_QUERY)
192 );
193 $cacheHash = $calculator->calculateCacheHash($parameters);
194
195 $GLOBALS['TYPO3_CONF_VARS'] = $configuration;
196 return $cacheHash;
197 }
198
199 /**
200 * @param array $typoScript
201 * @return ArrayValueInstruction
202 */
203 protected function createTypoLinkUrlInstruction(array $typoScript): ArrayValueInstruction
204 {
205 return (new ArrayValueInstruction(LinkHandlingController::class))
206 ->withArray([
207 '10' => 'TEXT',
208 '10.' => [
209 'typolink.' => array_merge(
210 $typoScript,
211 ['returnLast' => 'url']
212 )
213 ]
214 ]);
215 }
216
217 /**
218 * @param array $typoScript
219 * @return ArrayValueInstruction
220 */
221 protected function createHierarchicalMenuProcessorInstruction(array $typoScript): ArrayValueInstruction
222 {
223 return (new ArrayValueInstruction(LinkHandlingController::class))
224 ->withArray([
225 '10' => 'FLUIDTEMPLATE',
226 '10.' => [
227 'file' => 'typo3/sysext/core/Tests/Functional/Fixtures/Frontend/FluidJson.html',
228 'dataProcessing.' => [
229 '1' => 'TYPO3\\CMS\\Frontend\\DataProcessing\\MenuProcessor',
230 '1.' => array_merge(
231 $typoScript,
232 ['as' => 'results']
233 )
234 ],
235 ],
236 ]);
237 }
238
239 /**
240 * @param array $typoScript
241 * @return ArrayValueInstruction
242 */
243 protected function createLanguageMenuProcessorInstruction(array $typoScript): ArrayValueInstruction
244 {
245 return (new ArrayValueInstruction(LinkHandlingController::class))
246 ->withArray([
247 '10' => 'FLUIDTEMPLATE',
248 '10.' => [
249 'file' => 'typo3/sysext/core/Tests/Functional/Fixtures/Frontend/FluidJson.html',
250 'dataProcessing.' => [
251 '1' => 'TYPO3\\CMS\\Frontend\\DataProcessing\\LanguageMenuProcessor',
252 '1.' => array_merge(
253 $typoScript,
254 ['as' => 'results']
255 )
256 ],
257 ],
258 ]);
259 }
260
261 /**
262 * Filters and keeps only desired names.
263 *
264 * @param array $menu
265 * @param array $keepNames
266 * @return array
267 */
268 protected function filterMenu(
269 array $menu,
270 array $keepNames = ['title', 'link']
271 ): array {
272 if (!in_array('children', $keepNames)) {
273 $keepNames[] = 'children';
274 }
275 return array_map(
276 function (array $menuItem) use ($keepNames) {
277 $menuItem = array_filter(
278 $menuItem,
279 function (string $name) use ($keepNames) {
280 return in_array($name, $keepNames);
281 },
282 ARRAY_FILTER_USE_KEY
283 );
284 if (is_array($menuItem['children'] ?? null)) {
285 $menuItem['children'] = $this->filterMenu(
286 $menuItem['children'],
287 $keepNames
288 );
289 }
290 return $menuItem;
291 },
292 $menu
293 );
294 }
295
296 /**
297 * @param array $keys
298 * @param mixed $payload
299 * @return array
300 */
301 protected function populateToKeys(array $keys, $payload): array
302 {
303 $result = [];
304 foreach ($keys as $key) {
305 $result[$key] = $payload;
306 }
307 return $result;
308 }
309 }