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