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