[TASK] Move CSV fixtures handling to FunctionalTestCase 09/52609/2
authorTymoteusz Motylewski <t.motylewski@gmail.com>
Mon, 27 Feb 2017 08:45:03 +0000 (09:45 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Wed, 26 Apr 2017 16:33:08 +0000 (18:33 +0200)
Usage of CSV fixtures is now possible for all functional tests.
Previously it was available only for DataHandler tests.
This patch is backward compatible.

Resolves: #80007
Releases: master, 7.6
Change-Id: I6aa69825ac144b8c955b51a61060a822163511ca
Reviewed-on: https://review.typo3.org/52609
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/core/Classes/Tests/FunctionalTestCase.php
typo3/sysext/core/Tests/Functional/DataHandling/AbstractDataHandlerActionTestCase.php

index 68dd4da..4253fc0 100644 (file)
@@ -14,7 +14,9 @@ namespace TYPO3\CMS\Core\Tests;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Tests\Functional\DataHandling\Framework\DataSet;
 use TYPO3\CMS\Core\Tests\Functional\Framework\Frontend\Response;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Base test case class for functional tests, all TYPO3 CMS
@@ -321,6 +323,242 @@ abstract class FunctionalTestCase extends BaseTestCase
     }
 
     /**
+     * Import data from a CSV file to database
+     * Single file can contain data from multiple tables
+     *
+     * @param string $path absolute path to the CSV file containing the data set to load
+     */
+    public function importCSVDataSet($path)
+    {
+        $dataSet = DataSet::read($path, true);
+
+        foreach ($dataSet->getTableNames() as $tableName) {
+            foreach ($dataSet->getElements($tableName) as $element) {
+                $this->getDatabaseConnection()->exec_INSERTquery(
+                    $tableName,
+                    $element
+                );
+                $sqlError = $this->getDatabaseConnection()->sql_error();
+                if (!empty($sqlError)) {
+                    $this->fail('SQL Error for table "' . $tableName . '": ' . LF . $sqlError);
+                }
+            }
+        }
+    }
+
+    /**
+     * Compare data in database with CSV file
+     *
+     * @param string $path absolute path to the CSV file
+     */
+    protected function assertCSVDataSet($path)
+    {
+        $dataSet = DataSet::read($path);
+        $failMessages = [];
+
+        foreach ($dataSet->getTableNames() as $tableName) {
+            $hasUidField = ($dataSet->getIdIndex($tableName) !== null);
+            $records = $this->getAllRecords($tableName, $hasUidField);
+            foreach ($dataSet->getElements($tableName) as $assertion) {
+                $result = $this->assertInRecords($assertion, $records);
+                if ($result === false) {
+                    if ($hasUidField && empty($records[$assertion['uid']])) {
+                        $failMessages[] = 'Record "' . $tableName . ':' . $assertion['uid'] . '" not found in database';
+                        continue;
+                    }
+                    $recordIdentifier = $tableName . ($hasUidField ? ':' . $assertion['uid'] : '');
+                    $additionalInformation = ($hasUidField ? $this->renderRecords($assertion, $records[$assertion['uid']]) : $this->arrayToString($assertion));
+                    $failMessages[] = 'Assertion in data-set failed for "' . $recordIdentifier . '":' . LF . $additionalInformation;
+                    // Unset failed asserted record
+                    if ($hasUidField) {
+                        unset($records[$assertion['uid']]);
+                    }
+                } else {
+                    // Unset asserted record
+                    unset($records[$result]);
+                    // Increase assertion counter
+                    $this->assertTrue($result !== false);
+                }
+            }
+            if (!empty($records)) {
+                foreach ($records as $record) {
+                    $recordIdentifier = $tableName . ':' . $record['uid'];
+                    $emptyAssertion = array_fill_keys($dataSet->getFields($tableName), '[none]');
+                    $reducedRecord = array_intersect_key($record, $emptyAssertion);
+                    $additionalInformation = ($hasUidField ? $this->renderRecords($emptyAssertion, $reducedRecord) : $this->arrayToString($reducedRecord));
+                    $failMessages[] = 'Not asserted record found for "' . $recordIdentifier . '":' . LF . $additionalInformation;
+                }
+            }
+        }
+
+        if (!empty($failMessages)) {
+            $this->fail(implode(LF, $failMessages));
+        }
+    }
+
+    /**
+     * Check if $expectedRecord is present in $actualRecords array
+     * and compares if all column values from matches
+     *
+     * @param array $expectedRecord
+     * @param array $actualRecords
+     * @return bool|int|string false if record is not found or some column value doesn't match
+     */
+    protected function assertInRecords(array $expectedRecord, array $actualRecords)
+    {
+        foreach ($actualRecords as $index => $record) {
+            $differentFields = $this->getDifferentFields($expectedRecord, $record);
+
+            if (empty($differentFields)) {
+                return $index;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Fetches all records from a database table
+     * Helper method for assertCSVDataSet
+     *
+     * @param string $tableName
+     * @param bool $hasUidField
+     * @return array
+     */
+    protected function getAllRecords($tableName, $hasUidField = false)
+    {
+       $allRecords = [];
+
+        $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
+            '*',
+            $tableName,
+            '1=1',
+            '',
+            '',
+            '',
+            ($hasUidField ? 'uid' : '')
+        );
+
+        if (!empty($records)) {
+            $allRecords = $records;
+        }
+
+        return $allRecords;
+    }
+
+    /**
+     * Format array as human readable string. Used to format verbose error messages in assertCSVDataSet
+     *
+     * @param array $array
+     * @return string
+     */
+    protected function arrayToString(array $array)
+    {
+        $elements = [];
+        foreach ($array as $key => $value) {
+            if (is_array($value)) {
+                $value = $this->arrayToString($value);
+            }
+            $elements[] = "'" . $key . "' => '" . $value . "'";
+        }
+        return 'array(' . PHP_EOL . '   ' . implode(', ' . PHP_EOL . '   ', $elements) . PHP_EOL . ')' . PHP_EOL;
+    }
+
+    /**
+     * Format output showing difference between expected and actual db row in a human readable way
+     * Used to format verbose error messages in assertCSVDataSet
+     *
+     * @param array $assertion
+     * @param array $record
+     * @return string
+     */
+    protected function renderRecords(array $assertion, array $record)
+    {
+        $differentFields = $this->getDifferentFields($assertion, $record);
+        $columns = [
+            'fields' => ['Fields'],
+            'assertion' => ['Assertion'],
+            'record' => ['Record'],
+        ];
+        $lines = [];
+        $linesFromXmlValues = [];
+        $result = '';
+
+        foreach ($differentFields as $differentField) {
+            $columns['fields'][] = $differentField;
+            $columns['assertion'][] = ($assertion[$differentField] === null ? 'NULL' : $assertion[$differentField]);
+            $columns['record'][] = ($record[$differentField] === null ? 'NULL' : $record[$differentField]);
+        }
+
+        foreach ($columns as $columnIndex => $column) {
+            $columnLength = null;
+            foreach ($column as $value) {
+                if (strpos($value, '<?xml') === 0) {
+                    $value = '[see diff]';
+                }
+                $valueLength = strlen($value);
+                if (empty($columnLength) || $valueLength > $columnLength) {
+                    $columnLength = $valueLength;
+                }
+            }
+            foreach ($column as $valueIndex => $value) {
+                if (strpos($value, '<?xml') === 0) {
+                    if ($columnIndex === 'assertion') {
+                        try {
+                            $this->assertXmlStringEqualsXmlString((string)$value, (string)$record[$columns['fields'][$valueIndex]]);
+                        } catch (\PHPUnit_Framework_ExpectationFailedException $e) {
+                            $linesFromXmlValues[] = 'Diff for field "' . $columns['fields'][$valueIndex] . '":' . PHP_EOL . $e->getComparisonFailure()->getDiff();
+                        }
+                    }
+                    $value = '[see diff]';
+                }
+                $lines[$valueIndex][$columnIndex] = str_pad($value, $columnLength, ' ');
+            }
+        }
+
+        foreach ($lines as $line) {
+            $result .= implode('|', $line) . PHP_EOL;
+        }
+
+        foreach ($linesFromXmlValues as $lineFromXmlValues) {
+            $result .= PHP_EOL . $lineFromXmlValues . PHP_EOL;
+        }
+
+        return $result;
+    }
+
+    /**
+     * Compares two arrays containing db rows and returns array containing column names which don't match
+     * It's a helper method used in assertCSVDataSet
+     *
+     * @param array $assertion
+     * @param array $record
+     * @return array
+     */
+    protected function getDifferentFields(array $assertion, array $record)
+    {
+        $differentFields = [];
+
+        foreach ($assertion as $field => $value) {
+            if (strpos($value, '\\*') === 0) {
+                continue;
+            } elseif (strpos($value, '<?xml') === 0) {
+                try {
+                    $this->assertXmlStringEqualsXmlString((string)$value, (string)$record[$field]);
+                } catch (\PHPUnit_Framework_ExpectationFailedException $e) {
+                    $differentFields[] = $field;
+                }
+            } elseif ($value === null && $record[$field] !== $value) {
+                $differentFields[] = $field;
+            } elseif ((string)$record[$field] !== (string)$value) {
+                $differentFields[] = $field;
+            }
+        }
+
+        return $differentFields;
+    }
+
+    /**
      * @param int $pageId
      * @param array $typoScriptFiles
      */
index 7eb6192..9e6f25a 100644 (file)
@@ -14,7 +14,6 @@ namespace TYPO3\CMS\Core\Tests\Functional\DataHandling;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\Tests\Functional\DataHandling\Framework\DataSet;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -108,87 +107,14 @@ abstract class AbstractDataHandlerActionTestCase extends \TYPO3\CMS\Core\Tests\F
     {
         $fileName = rtrim($this->scenarioDataSetDirectory, '/') . '/' . $dataSetName . '.csv';
         $fileName = GeneralUtility::getFileAbsFileName($fileName);
-
-        $dataSet = DataSet::read($fileName, true);
-
-        foreach ($dataSet->getTableNames() as $tableName) {
-            foreach ($dataSet->getElements($tableName) as $element) {
-                $this->getDatabaseConnection()->exec_INSERTquery(
-                    $tableName,
-                    $element
-                );
-                $sqlError = $this->getDatabaseConnection()->sql_error();
-                if (!empty($sqlError)) {
-                    $this->fail('SQL Error for table "' . $tableName . '": ' . LF . $sqlError);
-                }
-            }
-        }
+        $this->importCSVDataSet($fileName);
     }
 
     protected function assertAssertionDataSet($dataSetName)
     {
         $fileName = rtrim($this->assertionDataSetDirectory, '/') . '/' . $dataSetName . '.csv';
         $fileName = GeneralUtility::getFileAbsFileName($fileName);
-
-        $dataSet = DataSet::read($fileName);
-        $failMessages = [];
-
-        foreach ($dataSet->getTableNames() as $tableName) {
-            $hasUidField = ($dataSet->getIdIndex($tableName) !== null);
-            $records = $this->getAllRecords($tableName, $hasUidField);
-            foreach ($dataSet->getElements($tableName) as $assertion) {
-                $result = $this->assertInRecords($assertion, $records);
-                if ($result === false) {
-                    if ($hasUidField && empty($records[$assertion['uid']])) {
-                        $failMessages[] = 'Record "' . $tableName . ':' . $assertion['uid'] . '" not found in database';
-                        continue;
-                    }
-                    $recordIdentifier = $tableName . ($hasUidField ? ':' . $assertion['uid'] : '');
-                    $additionalInformation = ($hasUidField ? $this->renderRecords($assertion, $records[$assertion['uid']]) : $this->arrayToString($assertion));
-                    $failMessages[] = 'Assertion in data-set failed for "' . $recordIdentifier . '":' . LF . $additionalInformation;
-                    // Unset failed asserted record
-                    if ($hasUidField) {
-                        unset($records[$assertion['uid']]);
-                    }
-                } else {
-                    // Unset asserted record
-                    unset($records[$result]);
-                    // Increase assertion counter
-                    $this->assertTrue($result !== false);
-                }
-            }
-            if (!empty($records)) {
-                foreach ($records as $record) {
-                    $recordIdentifier = $tableName . ':' . $record['uid'];
-                    $emptyAssertion = array_fill_keys($dataSet->getFields($tableName), '[none]');
-                    $reducedRecord = array_intersect_key($record, $emptyAssertion);
-                    $additionalInformation = ($hasUidField ? $this->renderRecords($emptyAssertion, $reducedRecord) : $this->arrayToString($reducedRecord));
-                    $failMessages[] = 'Not asserted record found for "' . $recordIdentifier . '":' . LF . $additionalInformation;
-                }
-            }
-        }
-
-        if (!empty($failMessages)) {
-            $this->fail(implode(LF, $failMessages));
-        }
-    }
-
-    /**
-     * @param array $assertion
-     * @param array $records
-     * @return bool|int|string
-     */
-    protected function assertInRecords(array $assertion, array $records)
-    {
-        foreach ($records as $index => $record) {
-            $differentFields = $this->getDifferentFields($assertion, $record);
-
-            if (empty($differentFields)) {
-                return $index;
-            }
-        }
-
-        return false;
+        $this->assertCSVDataSet($fileName);
     }
 
     /**
@@ -217,136 +143,6 @@ abstract class AbstractDataHandlerActionTestCase extends \TYPO3\CMS\Core\Tests\F
     }
 
     /**
-     * @param string $tableName
-     * @param bool $hasUidField
-     * @return array
-     */
-    protected function getAllRecords($tableName, $hasUidField = false)
-    {
-        $allRecords = [];
-
-        $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
-            '*',
-            $tableName,
-            '1=1',
-            '',
-            '',
-            '',
-            ($hasUidField ? 'uid' : '')
-        );
-
-        if (!empty($records)) {
-            $allRecords = $records;
-        }
-
-        return $allRecords;
-    }
-
-    /**
-     * @param array $array
-     * @return string
-     */
-    protected function arrayToString(array $array)
-    {
-        $elements = [];
-        foreach ($array as $key => $value) {
-            if (is_array($value)) {
-                $value = $this->arrayToString($value);
-            }
-            $elements[] = "'" . $key . "' => '" . $value . "'";
-        }
-        return 'array(' . PHP_EOL . '   ' . implode(', ' . PHP_EOL . '   ', $elements) . PHP_EOL . ')' . PHP_EOL;
-    }
-
-    /**
-     * @param array $assertion
-     * @param array $record
-     * @return string
-     */
-    protected function renderRecords(array $assertion, array $record)
-    {
-        $differentFields = $this->getDifferentFields($assertion, $record);
-        $columns = [
-            'fields' => ['Fields'],
-            'assertion' => ['Assertion'],
-            'record' => ['Record'],
-        ];
-        $lines = [];
-        $linesFromXmlValues = [];
-        $result = '';
-
-        foreach ($differentFields as $differentField) {
-            $columns['fields'][] = $differentField;
-            $columns['assertion'][] = ($assertion[$differentField] === null ? 'NULL' : $assertion[$differentField]);
-            $columns['record'][] = ($record[$differentField] === null ? 'NULL' : $record[$differentField]);
-        }
-
-        foreach ($columns as $columnIndex => $column) {
-            $columnLength = null;
-            foreach ($column as $value) {
-                if (strpos($value, '<?xml') === 0) {
-                    $value = '[see diff]';
-                }
-                $valueLength = strlen($value);
-                if (empty($columnLength) || $valueLength > $columnLength) {
-                    $columnLength = $valueLength;
-                }
-            }
-            foreach ($column as $valueIndex => $value) {
-                if (strpos($value, '<?xml') === 0) {
-                    if ($columnIndex === 'assertion') {
-                        try {
-                            $this->assertXmlStringEqualsXmlString((string)$value, (string)$record[$columns['fields'][$valueIndex]]);
-                        } catch (\PHPUnit_Framework_ExpectationFailedException $e) {
-                            $linesFromXmlValues[] = 'Diff for field "' . $columns['fields'][$valueIndex] . '":' . PHP_EOL . $e->getComparisonFailure()->getDiff();
-                        }
-                    }
-                    $value = '[see diff]';
-                }
-                $lines[$valueIndex][$columnIndex] = str_pad($value, $columnLength, ' ');
-            }
-        }
-
-        foreach ($lines as $line) {
-            $result .= implode('|', $line) . PHP_EOL;
-        }
-
-        foreach ($linesFromXmlValues as $lineFromXmlValues) {
-            $result .= PHP_EOL . $lineFromXmlValues . PHP_EOL;
-        }
-
-        return $result;
-    }
-
-    /**
-     * @param array $assertion
-     * @param array $record
-     * @return array
-     */
-    protected function getDifferentFields(array $assertion, array $record)
-    {
-        $differentFields = [];
-
-        foreach ($assertion as $field => $value) {
-            if (strpos($value, '\\*') === 0) {
-                continue;
-            } elseif (strpos($value, '<?xml') === 0) {
-                try {
-                    $this->assertXmlStringEqualsXmlString((string)$value, (string)$record[$field]);
-                } catch (\PHPUnit_Framework_ExpectationFailedException $e) {
-                    $differentFields[] = $field;
-                }
-            } elseif ($value === null && $record[$field] !== $value) {
-                $differentFields[] = $field;
-            } elseif ((string)$record[$field] !== (string)$value) {
-                $differentFields[] = $field;
-            }
-        }
-
-        return $differentFields;
-    }
-
-    /**
      * @return \TYPO3\CMS\Core\Tests\Functional\Framework\Constraint\RequestSection\HasRecordConstraint
      */
     protected function getRequestSectionHasRecordConstraint()