[!!!][TASK] Deprecate typo3conf/extTables.php functionality
[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 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18 use TYPO3\CMS\Core\Tests\Functional\DataHandling\Framework\DataSet;
19
20 /**
21 * Functional test for the DataHandler
22 */
23 abstract class AbstractDataHandlerActionTestCase extends \TYPO3\CMS\Core\Tests\FunctionalTestCase {
24
25 const VALUE_BackendUserId = 1;
26
27 /**
28 * @var string
29 */
30 protected $scenarioDataSetDirectory;
31
32 /**
33 * @var string
34 */
35 protected $assertionDataSetDirectory;
36
37 /**
38 * If this value is NULL, log entries are not considered.
39 * If it's an integer value, the number of log entries is asserted.
40 *
41 * @var NULL|int
42 */
43 protected $expectedErrorLogEntries = 0;
44
45 /**
46 * @var array
47 */
48 protected $testExtensionsToLoad = array(
49 'typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial',
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 );
58
59 /**
60 * @var array
61 */
62 protected $recordIds = array();
63
64 /**
65 * @var \TYPO3\CMS\Core\Tests\Functional\DataHandling\Framework\ActionService
66 */
67 protected $actionService;
68
69 /**
70 * @var \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
71 */
72 protected $backendUser;
73
74 protected function setUp() {
75 parent::setUp();
76
77 $this->backendUser = $this->setUpBackendUserFromFixture(self::VALUE_BackendUserId);
78 // By default make tests on live workspace
79 $this->backendUser->workspace = 0;
80
81 $this->actionService = $this->getActionService();
82 \TYPO3\CMS\Core\Core\Bootstrap::getInstance()->initializeLanguageObject();
83 }
84
85 protected function tearDown() {
86 $this->assertErrorLogEntries();
87 unset($this->actionService);
88 unset($this->recordIds);
89 parent::tearDown();
90 }
91
92 /**
93 * @return \TYPO3\CMS\Core\Tests\Functional\DataHandling\Framework\ActionService
94 */
95 protected function getActionService() {
96 return GeneralUtility::makeInstance(
97 \TYPO3\CMS\Core\Tests\Functional\DataHandling\Framework\ActionService::class
98 );
99 }
100
101 /**
102 * @param string $dataSetName
103 */
104 protected function importScenarioDataSet($dataSetName) {
105 $fileName = rtrim($this->scenarioDataSetDirectory, '/') . '/' . $dataSetName . '.csv';
106 $fileName = GeneralUtility::getFileAbsFileName($fileName);
107
108 $dataSet = DataSet::read($fileName);
109
110 foreach ($dataSet->getTableNames() as $tableName) {
111 foreach ($dataSet->getElements($tableName) as $element) {
112 $this->getDatabaseConnection()->exec_INSERTquery(
113 $tableName,
114 $element
115 );
116 $sqlError = $this->getDatabaseConnection()->sql_error();
117 if (!empty($sqlError)) {
118 $this->fail('SQL Error for table "' . $tableName . '": ' . LF . $sqlError);
119 }
120 }
121 }
122 }
123
124 protected function assertAssertionDataSet($dataSetName) {
125 $fileName = rtrim($this->assertionDataSetDirectory, '/') . '/' . $dataSetName . '.csv';
126 $fileName = GeneralUtility::getFileAbsFileName($fileName);
127
128 $dataSet = DataSet::read($fileName);
129 $failMessages = array();
130
131 foreach ($dataSet->getTableNames() as $tableName) {
132 $hasUidField = ($dataSet->getIdIndex($tableName) !== NULL);
133 $records = $this->getAllRecords($tableName, $hasUidField);
134 foreach ($dataSet->getElements($tableName) as $assertion) {
135 $result = $this->assertInRecords($assertion, $records);
136 if ($result === FALSE) {
137 if ($hasUidField && empty($records[$assertion['uid']])) {
138 $failMessages[] = 'Record "' . $tableName . ':' . $assertion['uid'] . '" not found in database';
139 continue;
140 }
141 $recordIdentifier = $tableName . ($hasUidField ? ':' . $assertion['uid'] : '');
142 $additionalInformation = ($hasUidField ? $this->renderRecords($assertion, $records[$assertion['uid']]) : $this->arrayToString($assertion));
143 $failMessages[] = 'Assertion in data-set failed for "' . $recordIdentifier . '":' . LF . $additionalInformation;
144 // Unset failed asserted record
145 if ($hasUidField) {
146 unset($records[$assertion['uid']]);
147 }
148 } else {
149 // Unset asserted record
150 unset($records[$result]);
151 // Increase assertion counter
152 $this->assertTrue($result !== FALSE);
153 }
154 }
155 if (!empty($records)) {
156 foreach ($records as $record) {
157 $recordIdentifier = $tableName . ':' . $record['uid'];
158 $emptyAssertion = array_fill_keys($dataSet->getFields($tableName), '[none]');
159 $reducedRecord = array_intersect_key($record, $emptyAssertion);
160 $additionalInformation = ($hasUidField ? $this->renderRecords($emptyAssertion, $reducedRecord) : $this->arrayToString($reducedRecord));
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 * Asserts correct number of warning and error log entries.
190 *
191 * @return void
192 */
193 protected function assertErrorLogEntries() {
194 if ($this->expectedErrorLogEntries === NULL) {
195 return;
196 }
197 $errorLogEntries = $this->getDatabaseConnection()->exec_SELECTgetRows('*', 'sys_log', 'error IN (1,2)');
198 $actualErrorLogEntries = count($errorLogEntries);
199 if ($actualErrorLogEntries === $this->expectedErrorLogEntries) {
200 $this->assertSame($this->expectedErrorLogEntries, $actualErrorLogEntries);
201 } else {
202 $failureMessage = 'Expected ' . $this->expectedErrorLogEntries . ' entries in sys_log, but got ' . $actualErrorLogEntries . LF;
203 foreach ($errorLogEntries as $entry) {
204 $entryData = unserialize($entry['log_data']);
205 $entryMessage = vsprintf($entry['details'], $entryData);
206 $failureMessage .= '* ' . $entryMessage . LF;
207 }
208 $this->fail($failureMessage);
209 }
210 }
211
212 /**
213 * @param string $tableName
214 * @param bool $hasUidField
215 * @return array
216 */
217 protected function getAllRecords($tableName, $hasUidField = FALSE) {
218 $allRecords = array();
219
220 $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
221 '*',
222 $tableName,
223 '1=1',
224 '',
225 '',
226 '',
227 ($hasUidField ? 'uid' : '')
228 );
229
230 if (!empty($records)) {
231 $allRecords = $records;
232 }
233
234 return $allRecords;
235 }
236
237 /**
238 * @param array $array
239 * @return string
240 */
241 protected function arrayToString(array $array) {
242 $elements = array();
243 foreach ($array as $key => $value) {
244 if (is_array($value)) {
245 $value = $this->arrayToString($value);
246 }
247 $elements[] = "'" . $key . "' => '" . $value . "'";
248 }
249 return 'array(' . PHP_EOL . ' ' . implode(', ' . PHP_EOL . ' ', $elements) . PHP_EOL . ')' . PHP_EOL;
250 }
251
252 /**
253 * @param array $assertion
254 * @param array $record
255 * @return string
256 */
257 protected function renderRecords(array $assertion, array $record) {
258 $differentFields = $this->getDifferentFields($assertion, $record);
259 $columns = array(
260 'fields' => array('Fields'),
261 'assertion' => array('Assertion'),
262 'record' => array('Record'),
263 );
264 $lines = array();
265 $linesFromXmlValues = array();
266 $result = '';
267
268 foreach ($differentFields as $differentField) {
269 $columns['fields'][] = $differentField;
270 $columns['assertion'][] = ($assertion[$differentField] === NULL ? 'NULL' : $assertion[$differentField]);
271 $columns['record'][] = ($record[$differentField] === NULL ? 'NULL' : $record[$differentField]);
272 }
273
274 foreach ($columns as $columnIndex => $column) {
275 $columnLength = NULL;
276 foreach ($column as $value) {
277 if (strpos($value, '<?xml') === 0) {
278 $value = '[see diff]';
279 }
280 $valueLength = strlen($value);
281 if (empty($columnLength) || $valueLength > $columnLength) {
282 $columnLength = $valueLength;
283 }
284 }
285 foreach ($column as $valueIndex => $value) {
286 if (strpos($value, '<?xml') === 0) {
287 if ($columnIndex === 'assertion') {
288 try {
289 $this->assertXmlStringEqualsXmlString((string)$value, (string)$record[$columns['fields'][$valueIndex]]);
290 } catch(\PHPUnit_Framework_ExpectationFailedException $e) {
291 $linesFromXmlValues[] = 'Diff for field "' . $columns['fields'][$valueIndex] . '":' . PHP_EOL . $e->getComparisonFailure()->getDiff();
292 }
293 }
294 $value = '[see diff]';
295 }
296 $lines[$valueIndex][$columnIndex] = str_pad($value, $columnLength, ' ');
297 }
298 }
299
300 foreach ($lines as $line) {
301 $result .= implode('|', $line) . PHP_EOL;
302 }
303
304 foreach ($linesFromXmlValues as $lineFromXmlValues) {
305 $result .= PHP_EOL . $lineFromXmlValues . PHP_EOL;
306 }
307
308 return $result;
309 }
310
311 /**
312 * @param array $assertion
313 * @param array $record
314 * @return array
315 */
316 protected function getDifferentFields(array $assertion, array $record) {
317 $differentFields = array();
318
319 foreach ($assertion as $field => $value) {
320 if (strpos($value, '\\*') === 0) {
321 continue;
322 } elseif (strpos($value, '<?xml') === 0) {
323 try {
324 $this->assertXmlStringEqualsXmlString((string)$value, (string)$record[$field]);
325 } catch (\PHPUnit_Framework_ExpectationFailedException $e) {
326 $differentFields[] = $field;
327 }
328 } elseif ($value === NULL && $record[$field] !== $value) {
329 $differentFields[] = $field;
330 } elseif ((string)$record[$field] !== (string)$value) {
331 $differentFields[] = $field;
332 }
333 }
334
335 return $differentFields;
336 }
337
338 /**
339 * @return \TYPO3\CMS\Core\Tests\Functional\Framework\Constraint\RequestSection\HasRecordConstraint
340 */
341 protected function getRequestSectionHasRecordConstraint() {
342 return new \TYPO3\CMS\Core\Tests\Functional\Framework\Constraint\RequestSection\HasRecordConstraint();
343 }
344
345 /**
346 * @return \TYPO3\CMS\Core\Tests\Functional\Framework\Constraint\RequestSection\DoesNotHaveRecordConstraint
347 */
348 protected function getRequestSectionDoesNotHaveRecordConstraint() {
349 return new \TYPO3\CMS\Core\Tests\Functional\Framework\Constraint\RequestSection\DoesNotHaveRecordConstraint();
350 }
351
352 /**
353 * @return \TYPO3\CMS\Core\Tests\Functional\Framework\Constraint\RequestSection\StructureHasRecordConstraint
354 */
355 protected function getRequestSectionStructureHasRecordConstraint() {
356 return new \TYPO3\CMS\Core\Tests\Functional\Framework\Constraint\RequestSection\StructureHasRecordConstraint();
357 }
358
359 /**
360 * @return \TYPO3\CMS\Core\Tests\Functional\Framework\Constraint\RequestSection\StructureDoesNotHaveRecordConstraint
361 */
362 protected function getRequestSectionStructureDoesNotHaveRecordConstraint() {
363 return new \TYPO3\CMS\Core\Tests\Functional\Framework\Constraint\RequestSection\StructureDoesNotHaveRecordConstraint();
364 }
365
366 }