[TASK] Use name-resolution instead of strings where possible: 16
[Packages/TYPO3.CMS.git] / typo3 / sysext / dbal / Tests / Unit / Database / DatabaseConnectionTest.php
1 <?php
2 namespace TYPO3\CMS\Dbal\Tests\Unit\Database;
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
19 /**
20 * Test case
21 */
22 class DatabaseConnectionTest extends AbstractTestCase {
23
24 /**
25 * @var \TYPO3\CMS\Dbal\Database\DatabaseConnection|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface
26 */
27 protected $subject;
28
29 /**
30 * Set up
31 */
32 public function setUp() {
33 $GLOBALS['TYPO3_LOADED_EXT'] = array();
34
35 /** @var \TYPO3\CMS\Dbal\Database\DatabaseConnection|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $subject */
36 $subject = $this->getAccessibleMock(\TYPO3\CMS\Dbal\Database\DatabaseConnection::class, array('getFieldInfoCache'), array(), '', FALSE);
37
38 // Disable caching
39 $mockCacheFrontend = $this->getMock(\TYPO3\CMS\Core\Cache\Frontend\PhpFrontend::class, array(), array(), '', FALSE);
40 $subject->expects($this->any())->method('getFieldInfoCache')->will($this->returnValue($mockCacheFrontend));
41
42 // Inject SqlParser - Its logic is tested with the tests, too.
43 $sqlParser = $this->getAccessibleMock(\TYPO3\CMS\Dbal\Database\SqlParser::class, array('dummy'), array(), '', FALSE);
44 $sqlParser->_set('databaseConnection', $subject);
45 $subject->SQLparser = $sqlParser;
46
47 // Mock away schema migration service from install tool
48 $installerSqlMock = $this->getMock(\TYPO3\CMS\Install\Service\SqlSchemaMigrationService::class, array('getFieldDefinitions_fileContent'), array(), '', FALSE);
49 $installerSqlMock->expects($this->any())->method('getFieldDefinitions_fileContent')->will($this->returnValue(array()));
50 $subject->_set('installerSql', $installerSqlMock);
51
52 $subject->initialize();
53 $subject->lastHandlerKey = '_DEFAULT';
54
55 $this->subject = $subject;
56 }
57
58 /**
59 * Creates a fake extension with a given table definition.
60 *
61 * @param string $tableDefinition SQL script to create the extension's tables
62 * @throws \RuntimeException
63 * @return void
64 */
65 protected function createFakeExtension($tableDefinition) {
66 // Prepare a fake extension configuration
67 $ext_tables = GeneralUtility::tempnam('ext_tables');
68 if (!GeneralUtility::writeFile($ext_tables, $tableDefinition)) {
69 throw new \RuntimeException('Can\'t write temporary ext_tables file.');
70 }
71 $this->testFilesToDelete[] = $ext_tables;
72 $GLOBALS['TYPO3_LOADED_EXT'] = array(
73 'test_dbal' => array(
74 'ext_tables.sql' => $ext_tables
75 )
76 );
77 // Append our test table to the list of existing tables
78 $this->subject->initialize();
79 }
80
81 /**
82 * @test
83 */
84 public function tableWithMappingIsDetected() {
85 $dbalConfiguration = array(
86 'mapping' => array(
87 'cf_cache_hash' => array(),
88 ),
89 );
90
91 /** @var \TYPO3\CMS\Dbal\Database\DatabaseConnection|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $subject */
92 $subject = $this->getAccessibleMock(\TYPO3\CMS\Dbal\Database\DatabaseConnection::class, array('getFieldInfoCache'), array(), '', FALSE);
93
94 $mockCacheFrontend = $this->getMock(\TYPO3\CMS\Core\Cache\Frontend\PhpFrontend::class, array(), array(), '', FALSE);
95 $subject->expects($this->any())->method('getFieldInfoCache')->will($this->returnValue($mockCacheFrontend));
96
97 $sqlParser = $this->getAccessibleMock(\TYPO3\CMS\Dbal\Database\SqlParser::class, array('dummy'), array(), '', FALSE);
98 $sqlParser->_set('databaseConnection', $subject);
99 $subject->SQLparser = $sqlParser;
100
101 $installerSqlMock = $this->getMock(\TYPO3\CMS\Install\Service\SqlSchemaMigrationService::class, array(), array(), '', FALSE);
102 $subject->_set('installerSql', $installerSqlMock);
103 $schemaMigrationResult = array(
104 'cf_cache_pages' => array(),
105 );
106 $installerSqlMock->expects($this->once())->method('getFieldDefinitions_fileContent')->will($this->returnValue($schemaMigrationResult));
107
108 $subject->conf = $dbalConfiguration;
109 $subject->initialize();
110 $subject->lastHandlerKey = '_DEFAULT';
111
112 $this->assertFalse($subject->_call('map_needMapping', 'cf_cache_pages'));
113 $cfCacheHashNeedsMapping = $subject->_call('map_needMapping', 'cf_cache_hash');
114 $this->assertEquals('cf_cache_hash', $cfCacheHashNeedsMapping[0]['table']);
115 }
116
117 /**
118 * @test
119 * @see http://forge.typo3.org/issues/21502
120 */
121 public function concatCanBeParsedAfterLikeOperator() {
122 $result = $this->subject->SELECTquery('*', 'sys_refindex, tx_dam_file_tracking', 'sys_refindex.tablename = \'tx_dam_file_tracking\'' . ' AND sys_refindex.ref_string LIKE CONCAT(tx_dam_file_tracking.file_path, tx_dam_file_tracking.file_name)');
123 $expected = 'SELECT * FROM sys_refindex, tx_dam_file_tracking WHERE sys_refindex.tablename = \'tx_dam_file_tracking\'';
124 $expected .= ' AND sys_refindex.ref_string LIKE CONCAT(tx_dam_file_tracking.file_path, tx_dam_file_tracking.file_name)';
125 $this->assertEquals($expected, $this->cleanSql($result));
126 }
127
128 /**
129 * @test
130 * @see http://forge.typo3.org/issues/20346
131 */
132 public function floatNumberCanBeStoredInDatabase() {
133 $this->createFakeExtension('
134 CREATE TABLE tx_test_dbal (
135 foo double default \'0\',
136 foobar int default \'0\'
137 );
138 ');
139 $data = array(
140 'foo' => 99.12,
141 'foobar' => -120
142 );
143 $result = $this->subject->INSERTquery('tx_test_dbal', $data);
144 $expected = 'INSERT INTO tx_test_dbal ( foo, foobar ) VALUES ( \'99.12\', \'-120\' )';
145 $this->assertEquals($expected, $this->cleanSql($result));
146 }
147
148 /**
149 * @test
150 * @see http://forge.typo3.org/issues/20427
151 */
152 public function positive64BitIntegerIsSupported() {
153 $this->createFakeExtension('
154 CREATE TABLE tx_test_dbal (
155 foo int default \'0\',
156 foobar bigint default \'0\'
157 );
158 ');
159 $data = array(
160 'foo' => 9223372036854775807,
161 'foobar' => 9223372036854775807
162 );
163 $result = $this->subject->INSERTquery('tx_test_dbal', $data);
164 $expected = 'INSERT INTO tx_test_dbal ( foo, foobar ) VALUES ( \'9223372036854775807\', \'9223372036854775807\' )';
165 $this->assertEquals($expected, $this->cleanSql($result));
166 }
167
168 /**
169 * @test
170 */
171 public function sqlForInsertWithMultipleRowsIsValid() {
172 $fields = array('uid', 'pid', 'title', 'body');
173 $rows = array(
174 array('1', '2', 'Title #1', 'Content #1'),
175 array('3', '4', 'Title #2', 'Content #2'),
176 array('5', '6', 'Title #3', 'Content #3')
177 );
178 $result = $this->subject->INSERTmultipleRows('tt_content', $fields, $rows);
179 $expected = 'INSERT INTO tt_content (uid, pid, title, body) VALUES ';
180 $expected .= '(\'1\', \'2\', \'Title #1\', \'Content #1\'), ';
181 $expected .= '(\'3\', \'4\', \'Title #2\', \'Content #2\'), ';
182 $expected .= '(\'5\', \'6\', \'Title #3\', \'Content #3\')';
183 $this->assertEquals($expected, $this->cleanSql($result));
184 }
185
186 /**
187 * @test
188 * @see http://forge.typo3.org/issues/16708
189 */
190 public function minFunctionAndInOperatorCanBeParsed() {
191 $result = $this->subject->SELECTquery('*', 'pages', 'MIN(uid) IN (1,2,3,4)');
192 $expected = 'SELECT * FROM pages WHERE MIN(uid) IN (1,2,3,4)';
193 $this->assertEquals($expected, $this->cleanSql($result));
194 }
195
196 /**
197 * @test
198 * @see http://forge.typo3.org/issues/16708
199 */
200 public function maxFunctionAndInOperatorCanBeParsed() {
201 $result = $this->subject->SELECTquery('*', 'pages', 'MAX(uid) IN (1,2,3,4)');
202 $expected = 'SELECT * FROM pages WHERE MAX(uid) IN (1,2,3,4)';
203 $this->assertEquals($expected, $this->cleanSql($result));
204 }
205
206 /**
207 * @test
208 * @see http://forge.typo3.org/issues/21514
209 */
210 public function likeBinaryOperatorIsKept() {
211 $result = $this->cleanSql($this->subject->SELECTquery('*', 'tt_content', 'bodytext LIKE BINARY \'test\''));
212 $expected = 'SELECT * FROM tt_content WHERE bodytext LIKE BINARY \'test\'';
213 $this->assertEquals($expected, $this->cleanSql($result));
214 }
215
216 /**
217 * @test
218 * @see http://forge.typo3.org/issues/21514
219 */
220 public function notLikeBinaryOperatorIsKept() {
221 $result = $this->cleanSql($this->subject->SELECTquery('*', 'tt_content', 'bodytext NOT LIKE BINARY \'test\''));
222 $expected = 'SELECT * FROM tt_content WHERE bodytext NOT LIKE BINARY \'test\'';
223 $this->assertEquals($expected, $this->cleanSql($result));
224 }
225
226 ///////////////////////////////////////
227 // Tests concerning prepared queries
228 ///////////////////////////////////////
229 /**
230 * @test
231 * @see http://forge.typo3.org/issues/23374
232 */
233 public function similarNamedParametersAreProperlyReplaced() {
234 $sql = 'SELECT * FROM cache WHERE tag = :tag1 OR tag = :tag10 OR tag = :tag100';
235 $parameterValues = array(
236 ':tag1' => 'tag-one',
237 ':tag10' => 'tag-two',
238 ':tag100' => 'tag-three'
239 );
240 $className = self::buildAccessibleProxy(\TYPO3\CMS\Core\Database\PreparedStatement::class);
241 $query = $sql;
242 $precompiledQueryParts = array();
243 $statement = new $className($sql, 'cache');
244 $statement->bindValues($parameterValues);
245 $parameters = $statement->_get('parameters');
246 $statement->_callRef('convertNamedPlaceholdersToQuestionMarks', $query, $parameters, $precompiledQueryParts);
247 $expectedQuery = 'SELECT * FROM cache WHERE tag = ? OR tag = ? OR tag = ?';
248 $expectedParameterValues = array(
249 0 => array(
250 'type' => \TYPO3\CMS\Core\Database\PreparedStatement::PARAM_STR,
251 'value' => 'tag-one',
252 ),
253 1 => array(
254 'type' => \TYPO3\CMS\Core\Database\PreparedStatement::PARAM_STR,
255 'value' => 'tag-two',
256 ),
257 2 => array(
258 'type' => \TYPO3\CMS\Core\Database\PreparedStatement::PARAM_STR,
259 'value' => 'tag-three',
260 ),
261 );
262 $this->assertEquals($expectedQuery, $query);
263 $this->assertEquals($expectedParameterValues, $parameters);
264 }
265
266 }