[TASK] Improve AbstractDataHandlerActionTestCase
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Functional / DataHandling / AbstractDataHandlerActionTestCase.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Functional\DataHandling;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2014 Oliver Hader <oliver.hader@typo3.org>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\CMS\Core\Tests\Functional\DataHandling\Framework\DataSet;
29 use TYPO3\CMS\Core\Tests\Functional\Framework\Frontend\Response;
30 use TYPO3\CMS\Core\Tests\Functional\Framework\Frontend\ResponseContent;
31
32 /**
33 * Functional test for the DataHandler
34 */
35 abstract class AbstractDataHandlerActionTestCase extends \TYPO3\CMS\Core\Tests\FunctionalTestCase {
36
37 const VALUE_BackendUserId = 1;
38
39 /**
40 * @var string
41 */
42 protected $dataSetDirectory;
43
44 /**
45 * @var array
46 */
47 protected $testExtensionsToLoad = array(
48 'typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial',
49 // 'typo3conf/ext/datahandler',
50 );
51
52 /**
53 * @var array
54 */
55 protected $pathsToLinkInTestInstance = array(
56 'typo3/sysext/core/Tests/Functional/Fixtures/Frontend/AdditionalConfiguration.php' => 'typo3conf/AdditionalConfiguration.php',
57 'typo3/sysext/core/Tests/Functional/Fixtures/Frontend/extTables.php' => 'typo3conf/extTables.php',
58 );
59
60 /**
61 * @var \TYPO3\CMS\Core\Tests\Functional\DataHandling\Framework\ActionService
62 */
63 protected $actionService;
64
65 /**
66 * @var \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
67 */
68 protected $backendUser;
69
70 public function setUp() {
71 parent::setUp();
72
73 $this->backendUser = $this->setUpBackendUserFromFixture(self::VALUE_BackendUserId);
74 // By default make tests on live workspace
75 $this->backendUser->workspace = 0;
76
77 $this->actionService = $this->getActionService();
78 \TYPO3\CMS\Core\Core\Bootstrap::getInstance()->initializeLanguageObject();
79 }
80
81 public function tearDown() {
82 unset($this->actionService);
83 }
84
85 /**
86 * @return \TYPO3\CMS\Core\DataHandling\DataHandler
87 */
88 protected function getDataHandler() {
89 $dataHandler = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler');
90 return $dataHandler;
91 }
92
93 /**
94 * @return \TYPO3\CMS\Core\Tests\Functional\DataHandling\Framework\ActionService
95 */
96 protected function getActionService() {
97 return GeneralUtility::makeInstance(
98 'TYPO3\\CMS\\Core\\Tests\\Functional\\DataHandling\\Framework\\ActionService',
99 $this->getDataHandler()
100 );
101 }
102
103 /**
104 * @param string $dataSetName
105 */
106 protected function importScenarioDataSet($dataSetName) {
107 $fileName = rtrim($this->dataSetDirectory, '/') . '/Scenario/' . $dataSetName . '.csv';
108 $fileName = GeneralUtility::getFileAbsFileName($fileName);
109
110 $dataSet = DataSet::read($fileName);
111
112 foreach ($dataSet->getTableNames() as $tableName) {
113 foreach ($dataSet->getElements($tableName) as $element) {
114 $this->getDatabase()->exec_INSERTquery(
115 $tableName,
116 $element
117 );
118 $sqlError = $this->getDatabase()->sql_error();
119 if (!empty($sqlError)) {
120 $this->fail('SQL Error for table "' . $tableName . '": ' . LF . $sqlError);
121 }
122 }
123 }
124 }
125
126 protected function assertAssertionDataSet($dataSetName) {
127 $fileName = rtrim($this->dataSetDirectory, '/') . '/Assertion/' . $dataSetName . '.csv';
128 $fileName = GeneralUtility::getFileAbsFileName($fileName);
129
130 $dataSet = DataSet::read($fileName);
131 $failMessages = array();
132
133 foreach ($dataSet->getTableNames() as $tableName) {
134 $hasUidField = ($dataSet->getIdIndex($tableName) !== NULL);
135 $records = $this->getAllRecords($tableName, $hasUidField);
136 foreach ($dataSet->getElements($tableName) as $assertion) {
137 $result = $this->assertInRecords($assertion, $records);
138 if ($result === FALSE) {
139 if ($hasUidField && empty($records[$assertion['uid']])) {
140 $failMessages[] = 'Record "' . $tableName . ':' . $assertion['uid'] . '" not found in database';
141 continue;
142 }
143 $recordIdentifier = $tableName . ($hasUidField ? ':' . $assertion['uid'] : '');
144 $additionalInformation = ($hasUidField ? $this->renderRecords($assertion, $records[$assertion['uid']]) : $this->arrayToString($assertion));
145 $failMessages[] = 'Assertion in data-set failed for "' . $recordIdentifier . '":' . LF . $additionalInformation;
146 // Unset failed asserted record
147 if ($hasUidField) {
148 unset($records[$assertion['uid']]);
149 }
150 } else {
151 // Unset asserted record
152 unset($records[$result]);
153 // Increase assertion counter
154 $this->assertTrue($result !== FALSE);
155 }
156 }
157 if (!empty($records)) {
158 foreach ($records as $record) {
159 $recordIdentifier = $tableName . ':' . $record['uid'];
160 $additionalInformation = $this->arrayToString($record);
161 $failMessages[] = 'Not asserted record found for "' . $recordIdentifier . '":' . LF . $additionalInformation;
162 }
163 }
164 }
165
166 if (!empty($failMessages)) {
167 $this->fail(implode(LF, $failMessages));
168 }
169 }
170
171 /**
172 * @param array $assertion
173 * @param array $records
174 * @return bool|int|string
175 */
176 protected function assertInRecords(array $assertion, array $records) {
177 foreach ($records as $index => $record) {
178 $differentFields = $this->getDifferentFields($assertion, $record);
179
180 if (empty($differentFields)) {
181 return $index;
182 }
183 }
184
185 return FALSE;
186 }
187
188 /**
189 * @param string $tableName
190 * @param bool $hasUidField
191 * @return array
192 */
193 protected function getAllRecords($tableName, $hasUidField = FALSE) {
194 $allRecords = array();
195
196 $records = $this->getDatabase()->exec_SELECTgetRows(
197 '*',
198 $tableName,
199 '1=1',
200 '',
201 '',
202 '',
203 ($hasUidField ? 'uid' : '')
204 );
205
206 if (!empty($records)) {
207 $allRecords = $records;
208 }
209
210 return $allRecords;
211 }
212
213 /**
214 * @param array $array
215 * @return string
216 */
217 protected function arrayToString(array $array) {
218 $elements = array();
219 foreach ($array as $key => $value) {
220 if (is_array($value)) {
221 $value = $this->arrayToString($value);
222 }
223 $elements[] = "'" . $key . "' => '" . $value . "'";
224 }
225 return 'array(' . PHP_EOL . ' ' . implode(', ' . PHP_EOL . ' ', $elements) . PHP_EOL . ')' . PHP_EOL;
226 }
227
228 /**
229 * @param array $assertion
230 * @param array $record
231 * @return string
232 */
233 protected function renderRecords(array $assertion, array $record) {
234 $differentFields = $this->getDifferentFields($assertion, $record);
235 $columns = array(
236 'fields' => array('Fields'),
237 'assertion' => array('Assertion'),
238 'record' => array('Record'),
239 );
240 $lines = array();
241 $linesFromXmlValues = array();
242 $result = '';
243
244 foreach ($differentFields as $differentField) {
245 $columns['fields'][] = $differentField;
246 $columns['assertion'][] = ($assertion[$differentField] === NULL ? 'NULL' : $assertion[$differentField]);
247 $columns['record'][] = ($record[$differentField] === NULL ? 'NULL' : $record[$differentField]);
248 }
249
250 foreach ($columns as $columnIndex => $column) {
251 $columnLength = NULL;
252 foreach ($column as $value) {
253 if (strpos($value, '<?xml') === 0) {
254 $value = '[see diff]';
255 }
256 $valueLength = strlen($value);
257 if (empty($columnLength) || $valueLength > $columnLength) {
258 $columnLength = $valueLength;
259 }
260 }
261 foreach ($column as $valueIndex => $value) {
262 if (strpos($value, '<?xml') === 0) {
263 if ($columnIndex === 'assertion') {
264 try {
265 $this->assertXmlStringEqualsXmlString((string)$value, (string)$record[$columns['fields'][$valueIndex]]);
266 } catch(\PHPUnit_Framework_ExpectationFailedException $e) {
267 $linesFromXmlValues[] = 'Diff for field "' . $columns['fields'][$valueIndex] . '":' . PHP_EOL . $e->getComparisonFailure()->getDiff();
268 }
269 }
270 $value = '[see diff]';
271 }
272 $lines[$valueIndex][$columnIndex] = str_pad($value, $columnLength, ' ');
273 }
274 }
275
276 foreach ($lines as $line) {
277 $result .= implode('|', $line) . PHP_EOL;
278 }
279
280 foreach ($linesFromXmlValues as $lineFromXmlValues) {
281 $result .= PHP_EOL . $lineFromXmlValues . PHP_EOL;
282 }
283
284 return $result;
285 }
286
287 /**
288 * @param array $assertion
289 * @param array $record
290 * @return array
291 */
292 protected function getDifferentFields(array $assertion, array $record) {
293 $differentFields = array();
294
295 foreach ($assertion as $field => $value) {
296 if (strpos($value, '\\*') === 0) {
297 continue;
298 } elseif (strpos($value, '<?xml') === 0) {
299 try {
300 $this->assertXmlStringEqualsXmlString((string)$value, (string)$record[$field]);
301 } catch (\PHPUnit_Framework_ExpectationFailedException $e) {
302 $differentFields[] = $field;
303 }
304 } elseif ($value === NULL && $record[$field] !== $value) {
305 $differentFields[] = $field;
306 } elseif ((string)$record[$field] !== (string)$value) {
307 $differentFields[] = $field;
308 }
309 }
310
311 return $differentFields;
312 }
313
314 /**
315 * @param ResponseContent $responseContent
316 * @param string $structureRecordIdentifier
317 * @param string $structureFieldName
318 * @param string $tableName
319 * @param string $fieldName
320 * @param string|array $values
321 */
322 protected function assertResponseContentStructureHasRecords(ResponseContent $responseContent, $structureRecordIdentifier, $structureFieldName, $tableName, $fieldName, $values) {
323 $nonMatchingVariants = array();
324
325 foreach ($responseContent->findStructures($structureRecordIdentifier, $structureFieldName) as $path => $structure) {
326 $nonMatchingValues = $this->getNonMatchingValuesFrontendResponseRecords($structure, $tableName, $fieldName, $values);
327
328 if (empty($nonMatchingValues)) {
329 // Increase assertion counter
330 $this->assertEmpty($nonMatchingValues);
331 return;
332 }
333
334 $nonMatchingVariants[$path] = $nonMatchingValues;
335 }
336
337 $nonMatchingMessage = '';
338 foreach ($nonMatchingVariants as $path => $nonMatchingValues) {
339 $nonMatchingMessage .= '* ' . $path . ': ' . implode(', ', $nonMatchingValues);
340 }
341
342 $this->fail('Could not assert all values for "' . $tableName . '.' . $fieldName . '"' . LF . $nonMatchingMessage);
343 }
344
345 /**
346 * @param ResponseContent $responseContent
347 * @param string $structureRecordIdentifier
348 * @param string $structureFieldName
349 * @param string $tableName
350 * @param string $fieldName
351 * @param string|array $values
352 */
353 protected function assertResponseContentStructureDoesNotHaveRecords(ResponseContent $responseContent, $structureRecordIdentifier, $structureFieldName, $tableName, $fieldName, $values) {
354 if (is_string($values)) {
355 $values = array($values);
356 }
357
358 $matchingVariants = array();
359
360 foreach ($responseContent->findStructures($structureRecordIdentifier, $structureFieldName) as $path => $structure) {
361 $nonMatchingValues = $this->getNonMatchingValuesFrontendResponseRecords($structure, $tableName, $fieldName, $values);
362 $matchingValues = array_diff($values, $nonMatchingValues);
363
364 if (!empty($matchingValues)) {
365 $matchingVariants[$path] = $matchingValues;
366 }
367 }
368
369 if (empty($matchingVariants)) {
370 // Increase assertion counter
371 $this->assertEmpty($matchingVariants);
372 return;
373 }
374
375 $matchingMessage = '';
376 foreach ($matchingVariants as $path => $matchingValues) {
377 $matchingMessage .= '* ' . $path . ': ' . implode(', ', $matchingValues);
378 }
379
380 $this->fail('Could not assert not having values for "' . $tableName . '.' . $fieldName . '"' . LF . $matchingMessage);
381 }
382
383 /**
384 * @param ResponseContent $responseContent
385 * @param string $tableName
386 * @param string $fieldName
387 * @param string|array $values
388 */
389 protected function assertResponseContentHasRecords(ResponseContent $responseContent, $tableName, $fieldName, $values) {
390 $nonMatchingValues = $this->getNonMatchingValuesFrontendResponseRecords($responseContent->getRecords(), $tableName, $fieldName, $values);
391
392 if (!empty($nonMatchingValues)) {
393 $this->fail('Could not assert all values for "' . $tableName . '.' . $fieldName . '": ' . implode(', ', $nonMatchingValues));
394 }
395
396 // Increase assertion counter
397 $this->assertEmpty($nonMatchingValues);
398 }
399
400 /**
401 * @param ResponseContent $responseContent
402 * @param string $tableName
403 * @param string $fieldName
404 * @param string|array $values
405 */
406 protected function assertResponseContentDoesNotHaveRecords(ResponseContent $responseContent, $tableName, $fieldName, $values) {
407 if (is_string($values)) {
408 $values = array($values);
409 }
410
411 $nonMatchingValues = $this->getNonMatchingValuesFrontendResponseRecords($responseContent->getRecords(), $tableName, $fieldName, $values);
412 $matchingValues = array_diff($values, $nonMatchingValues);
413
414 if (!empty($matchingValues)) {
415 $this->fail('Could not assert not having values for "' . $tableName . '.' . $fieldName . '": ' . implode(', ', $matchingValues));
416 }
417
418 // Increase assertion counter
419 $this->assertTrue(TRUE);
420 }
421
422 /**
423 * @param string|array $data
424 * @param string $tableName
425 * @param string $fieldName
426 * @param string|array $values
427 * @return array
428 */
429 protected function getNonMatchingValuesFrontendResponseRecords($data, $tableName, $fieldName, $values) {
430 if (empty($data) || !is_array($data)) {
431 $this->fail('Frontend Response data does not have any records');
432 }
433
434 if (is_string($values)) {
435 $values = array($values);
436 }
437
438 foreach ($data as $recordIdentifier => $recordData) {
439 if (strpos($recordIdentifier, $tableName . ':') !== 0) {
440 continue;
441 }
442
443 if (($foundValueIndex = array_search($recordData[$fieldName], $values)) !== FALSE) {
444 unset($values[$foundValueIndex]);
445 }
446 }
447
448 return $values;
449 }
450
451 }