‪TYPO3CMS  ‪main
ConnectionTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Doctrine\DBAL\Configuration;
21 use Doctrine\DBAL\Driver\AbstractMySQLDriver;
22 use Doctrine\DBAL\Result;
23 use PHPUnit\Framework\Attributes\DataProvider;
24 use PHPUnit\Framework\Attributes\Test;
25 use PHPUnit\Framework\MockObject\MockObject;
28 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
31 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
32 
33 final class ‪ConnectionTest extends UnitTestCase
34 {
35  protected ‪Connection&MockObject ‪$connection;
36 
40  protected function ‪setUp(): void
41  {
42  parent::setUp();
43  $this->connection = $this->getMockBuilder(Connection::class)
44  ->onlyMethods(
45  [
46  'connect',
47  'ensureDatabaseValueTypes',
48  'executeQuery',
49  'executeStatement',
50  'getDatabasePlatform',
51  'getDriver',
52  'getExpressionBuilder',
53  'getNativeConnection',
54  'getServerVersion',
55  ]
56  )
57  ->setConstructorArgs([[], $this->createMock(AbstractMySQLDriver::class), new Configuration(), null])
58  ->getMock();
59 
60  $this->connection
61  ->method('getExpressionBuilder')
62  ->willReturn(GeneralUtility::makeInstance(ExpressionBuilder::class, $this->connection));
63 
64  $this->connection
65  ->method('connect');
66 
67  $this->connection
68  ->method('getDatabasePlatform')
69  ->willReturn(new ‪MockPlatform());
70  }
71 
72  #[Test]
74  {
75  self::assertInstanceOf(QueryBuilder::class, $this->connection->createQueryBuilder());
76  }
77 
78  public static function ‪quoteIdentifierDataProvider(): array
79  {
80  return [
81  'SQL star' => [
82  '*',
83  '*',
84  ],
85  'fieldname' => [
86  'aField',
87  '"aField"',
88  ],
89  'whitespace' => [
90  'with blanks',
91  '"with blanks"',
92  ],
93  'double quotes' => [
94  '"double" quotes',
95  '"""double"" quotes"',
96  ],
97  'single quotes' => [
98  "'single'",
99  '"\'single\'"',
100 
101  ],
102  'multiple double quotes' => [
103  '""multiple""',
104  '"""""multiple"""""',
105  ],
106  'multiple single quotes' => [
107  "''multiple''",
108  '"\'\'multiple\'\'"',
109  ],
110  'backticks' => [
111  '`backticks`',
112  '"`backticks`"',
113  ],
114  'slashes' => [
115  '/slashes/',
116  '"/slashes/"',
117  ],
118  'backslashes' => [
119  '\\backslashes\\',
120  '"\\backslashes\\"',
121  ],
122  ];
123  }
124 
125  #[DataProvider('quoteIdentifierDataProvider')]
126  #[Test]
127  public function ‪quoteIdentifier(string $input, string $expected): void
128  {
129  self::assertSame($expected, $this->connection->quoteIdentifier($input));
130  }
131 
132  #[Test]
133  public function ‪quoteIdentifiers(): void
134  {
135  $input = [
136  'aField',
137  'anotherField',
138  ];
139 
140  $expected = [
141  '"aField"',
142  '"anotherField"',
143  ];
144 
145  self::assertSame($expected, $this->connection->quoteIdentifiers($input));
146  }
147 
148  public static function ‪insertQueriesDataProvider(): array
149  {
150  return [
151  'single value' => [
152  ['aTestTable', ['aField' => 'aValue']],
153  'INSERT INTO "aTestTable" ("aField") VALUES (?)',
154  ['aValue'],
155  [],
156  ],
157  'multiple values' => [
158  ['aTestTable', ['aField' => 'aValue', 'bField' => 'bValue']],
159  'INSERT INTO "aTestTable" ("aField", "bField") VALUES (?, ?)',
160  ['aValue', 'bValue'],
161  [],
162  ],
163  'with types' => [
164  ['aTestTable', ['aField' => 'aValue', 'bField' => 'bValue'], [‪Connection::PARAM_STR, ‪Connection::PARAM_STR]],
165  'INSERT INTO "aTestTable" ("aField", "bField") VALUES (?, ?)',
166  ['aValue', 'bValue'],
168  ],
169  'with types for field' => [
170  [
171  'aTestTable',
172  ['aField' => 123, 'bField' => 'bValue'],
173  ['aField' => ‪Connection::PARAM_INT, 'bField' => ‪Connection::PARAM_LOB],
174  ],
175  'INSERT INTO "aTestTable" ("aField", "bField") VALUES (?, ?)',
176  [123, 'bValue'],
178  ],
179  ];
180  }
181 
182  #[DataProvider('insertQueriesDataProvider')]
183  #[Test]
184  public function ‪insertQueries(array ‪$args, string $expectedQuery, array $expectedValues, array $expectedTypes): void
185  {
186  $this->connection->expects(self::once())
187  ->method('executeStatement')
188  ->with($expectedQuery, $expectedValues, $expectedTypes)
189  ->willReturn(1);
190 
191  $this->connection->insert(...‪$args);
192  }
193 
194  #[Test]
195  public function ‪bulkInsert(): void
196  {
197  $this->connection->expects(self::once())
198  ->method('executeStatement')
199  ->with('INSERT INTO "aTestTable" ("aField") VALUES (?), (?)', ['aValue', 'anotherValue'])
200  ->willReturn(2);
201 
202  $this->connection->bulkInsert('aTestTable', [['aField' => 'aValue'], ['aField' => 'anotherValue']], ['aField']);
203  }
204 
205  public static function ‪updateQueriesDataProvider(): array
206  {
207  return [
208  'single value' => [
209  ['aTestTable', ['aField' => 'aValue'], ['uid' => 1]],
210  'UPDATE "aTestTable" SET "aField" = ? WHERE "uid" = ?',
211  ['aValue', 1],
212  [],
213  ],
214  'multiple values' => [
215  ['aTestTable', ['aField' => 'aValue', 'bField' => 'bValue'], ['uid' => 1]],
216  'UPDATE "aTestTable" SET "aField" = ?, "bField" = ? WHERE "uid" = ?',
217  ['aValue', 'bValue', 1],
218  [],
219  ],
220  'with types' => [
221  ['aTestTable', ['aField' => 'aValue'], ['uid' => 1], [‪Connection::PARAM_STR]],
222  'UPDATE "aTestTable" SET "aField" = ? WHERE "uid" = ?',
223  ['aValue', 1],
225  ],
226  'with types for field' => [
227  ['aTestTable', ['aField' => 'aValue'], ['uid' => 1], ['aField' => ‪Connection::PARAM_LOB]],
228  'UPDATE "aTestTable" SET "aField" = ? WHERE "uid" = ?',
229  ['aValue', 1],
231  ],
232  ];
233  }
234 
235  #[DataProvider('updateQueriesDataProvider')]
236  #[Test]
237  public function ‪updateQueries(array ‪$args, string $expectedQuery, array $expectedValues, array $expectedTypes): void
238  {
239  // @todo drop else branch and condition once doctrine/dbal is requried in version 2.11.0 minimum
240  if (method_exists(Connection::class, 'executeStatement')) {
241  $this->connection->expects(self::once())
242  ->method('executeStatement')
243  ->with($expectedQuery, $expectedValues, $expectedTypes)
244  ->willReturn(1);
245  } else {
246  $this->connection->expects(self::once())
247  ->method('executeUpdate')
248  ->with($expectedQuery, $expectedValues, $expectedTypes)
249  ->willReturn(1);
250  }
251 
252  $this->connection->update(...‪$args);
253  }
254 
255  public static function ‪deleteQueriesDataProvider(): array
256  {
257  return [
258  'single condition' => [
259  ['aTestTable', ['aField' => 'aValue']],
260  'DELETE FROM "aTestTable" WHERE "aField" = ?',
261  ['aValue'],
262  [],
263  ],
264  'multiple conditions' => [
265  ['aTestTable', ['aField' => 'aValue', 'bField' => 'bValue']],
266  'DELETE FROM "aTestTable" WHERE "aField" = ? AND "bField" = ?',
267  ['aValue', 'bValue'],
268  [],
269  ],
270  'with types' => [
271  ['aTestTable', ['aField' => 'aValue'], [‪Connection::PARAM_STR]],
272  'DELETE FROM "aTestTable" WHERE "aField" = ?',
273  ['aValue'],
275  ],
276  'with types for field' => [
277  ['aTestTable', ['aField' => 'aValue'], ['aField' => ‪Connection::PARAM_STR]],
278  'DELETE FROM "aTestTable" WHERE "aField" = ?',
279  ['aValue'],
281  ],
282  ];
283  }
284 
285  #[DataProvider('deleteQueriesDataProvider')]
286  #[Test]
287  public function ‪deleteQueries(array ‪$args, string $expectedQuery, array $expectedValues, array $expectedTypes): void
288  {
289  // @todo drop else branch and condition once doctrine/dbal is requried in version 2.11.0 minimum
290  if (method_exists(Connection::class, 'executeStatement')) {
291  $this->connection->expects(self::once())
292  ->method('executeStatement')
293  ->with($expectedQuery, $expectedValues, $expectedTypes)
294  ->willReturn(1);
295  } else {
296  $this->connection->expects(self::once())
297  ->method('executeUpdate')
298  ->with($expectedQuery, $expectedValues, $expectedTypes)
299  ->willReturn(1);
300  }
301 
302  $this->connection->delete(...‪$args);
303  }
304 
313  public static function ‪selectQueriesDataProvider(): array
314  {
315  return [
316  'all columns' => [
317  [['*'], 'aTable'],
318  'SELECT * FROM "aTable"',
319  [],
320  ],
321  'subset of columns' => [
322  [['aField', 'anotherField'], 'aTable'],
323  'SELECT "aField", "anotherField" FROM "aTable"',
324  [],
325  ],
326  'conditions' => [
327  [['*'], 'aTable', ['aField' => 'aValue']],
328  'SELECT * FROM "aTable" WHERE "aField" = :dcValue1',
329  ['dcValue1' => 'aValue'],
330  ],
331  'grouping' => [
332  [['*'], 'aTable', [], ['aField']],
333  'SELECT * FROM "aTable" GROUP BY "aField"',
334  [],
335  ],
336  'ordering' => [
337  [['*'], 'aTable', [], [], ['aField' => 'ASC']],
338  'SELECT * FROM "aTable" ORDER BY "aField" ASC',
339  [],
340  ],
341  'limit' => [
342  [['*'], 'aTable', [], [], [], 1],
343  'SELECT * FROM "aTable" LIMIT 1',
344  [],
345  ],
346  'offset' => [
347  [['*'], 'aTable', [], [], [], 1, 10],
348  'SELECT * FROM "aTable" LIMIT 1 OFFSET 10',
349  [],
350  ],
351  'everything' => [
352  [
353  ['aField', 'anotherField'],
354  'aTable',
355  ['aField' => 'aValue'],
356  ['anotherField'],
357  ['aField' => 'ASC'],
358  1,
359  10,
360  ],
361  'SELECT "aField", "anotherField" FROM "aTable" WHERE "aField" = :dcValue1 ' .
362  'GROUP BY "anotherField" ORDER BY "aField" ASC LIMIT 1 OFFSET 10',
363  ['dcValue1' => 'aValue'],
364  ],
365  ];
366  }
367 
368  #[DataProvider('selectQueriesDataProvider')]
369  #[Test]
370  public function ‪selectQueries(array ‪$args, string $expectedQuery, array $expectedParameters): void
371  {
372  $resultStatement = $this->createMock(Result::class);
373 
374  $this->connection->expects(self::once())
375  ->method('executeQuery')
376  ->with($expectedQuery, $expectedParameters)
377  ->willReturn($resultStatement);
378 
379  $this->connection->select(...‪$args);
380  }
381 
390  public static function ‪countQueriesDataProvider(): array
391  {
392  return [
393  'all columns' => [
394  ['*', 'aTable', []],
395  'SELECT COUNT(*) FROM "aTable"',
396  [],
397  ],
398  'specified columns' => [
399  ['aField', 'aTable', []],
400  'SELECT COUNT("aField") FROM "aTable"',
401  [],
402  ],
403  'conditions' => [
404  ['aTable.aField', 'aTable', ['aField' => 'aValue']],
405  'SELECT COUNT("aTable"."aField") FROM "aTable" WHERE "aField" = :dcValue1',
406  ['dcValue1' => 'aValue'],
407  ],
408  ];
409  }
410 
411  #[DataProvider('countQueriesDataProvider')]
412  #[Test]
413  public function ‪countQueries(array ‪$args, string $expectedQuery, array $expectedParameters): void
414  {
415  $resultStatement = $this->createMock(Result::class);
416 
417  $resultStatement->expects(self::once())
418  ->method('fetchOne')
419  ->willReturn(false);
420  $this->connection->expects(self::once())
421  ->method('executeQuery')
422  ->with($expectedQuery, $expectedParameters)
423  ->willReturn($resultStatement);
424  $this->connection->count(...‪$args);
425  }
426 
427  #[Test]
428  public function ‪truncateQuery(): void
429  {
430  $this->connection->expects(self::once())
431  ->method('executeStatement')
432  ->with('TRUNCATE "aTestTable"')
433  ->willReturn(0);
434 
435  $this->connection->truncate('aTestTable', false);
436  }
437 
438  #[Test]
440  {
441  $this->connection
442  ->method('getServerVersion')
443  ->willReturn('5.7.11');
444 
445  self::assertSame('5.7.11', $this->connection->getServerVersion());
446  }
447 
448  #[Test]
450  {
451  $this->connection
452  ->method('getServerVersion')
453  ->willReturn('5.7.11');
454 
455  self::assertSame('Mock 5.7.11', $this->connection->getPlatformServerVersion());
456  }
457 }
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\updateQueries
‪updateQueries(array $args, string $expectedQuery, array $expectedValues, array $expectedTypes)
Definition: ConnectionTest.php:237
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:52
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:40
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\setUp
‪setUp()
Definition: ConnectionTest.php:40
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\getPlatformServerVersionReportsPlatformVersion
‪getPlatformServerVersionReportsPlatformVersion()
Definition: ConnectionTest.php:449
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\quoteIdentifierDataProvider
‪static quoteIdentifierDataProvider()
Definition: ConnectionTest.php:78
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\createQueryBuilderReturnsInstanceOfTypo3QueryBuilder
‪createQueryBuilderReturnsInstanceOfTypo3QueryBuilder()
Definition: ConnectionTest.php:73
‪TYPO3\CMS\Core\Database\Connection\PARAM_STR
‪const PARAM_STR
Definition: Connection.php:57
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\insertQueries
‪insertQueries(array $args, string $expectedQuery, array $expectedValues, array $expectedTypes)
Definition: ConnectionTest.php:184
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\countQueries
‪countQueries(array $args, string $expectedQuery, array $expectedParameters)
Definition: ConnectionTest.php:413
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\getServerVersionReportsServerVersionOnly
‪getServerVersionReportsServerVersionOnly()
Definition: ConnectionTest.php:439
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\quoteIdentifier
‪quoteIdentifier(string $input, string $expected)
Definition: ConnectionTest.php:127
‪TYPO3\CMS\Core\Tests\Unit\Database
Definition: ConnectionPoolTest.php:18
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\$connection
‪Connection &MockObject $connection
Definition: ConnectionTest.php:35
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\deleteQueries
‪deleteQueries(array $args, string $expectedQuery, array $expectedValues, array $expectedTypes)
Definition: ConnectionTest.php:287
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest
Definition: ConnectionTest.php:34
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\selectQueries
‪selectQueries(array $args, string $expectedQuery, array $expectedParameters)
Definition: ConnectionTest.php:370
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\deleteQueriesDataProvider
‪static deleteQueriesDataProvider()
Definition: ConnectionTest.php:255
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\countQueriesDataProvider
‪static countQueriesDataProvider()
Definition: ConnectionTest.php:390
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\bulkInsert
‪bulkInsert()
Definition: ConnectionTest.php:195
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\truncateQuery
‪truncateQuery()
Definition: ConnectionTest.php:428
‪$args
‪$args
Definition: validateRstFiles.php:258
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\quoteIdentifiers
‪quoteIdentifiers()
Definition: ConnectionTest.php:133
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\updateQueriesDataProvider
‪static updateQueriesDataProvider()
Definition: ConnectionTest.php:205
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\selectQueriesDataProvider
‪static selectQueriesDataProvider()
Definition: ConnectionTest.php:313
‪TYPO3\CMS\Core\Tests\Unit\Database\ConnectionTest\insertQueriesDataProvider
‪static insertQueriesDataProvider()
Definition: ConnectionTest.php:148
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Tests\Unit\Database\Mocks\MockPlatform\MockPlatform
Definition: MockPlatform.php:32
‪TYPO3\CMS\Core\Database\Connection\PARAM_LOB
‪const PARAM_LOB
Definition: Connection.php:62