[TASK] dbal: skip update suggestions for equivalent fields in Install Tool
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Tests / Unit / Service / SqlSchemaMigrationServiceTest.php
1 <?php
2 namespace TYPO3\CMS\Install\Tests\Unit\Service;
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\Install\Service\SqlSchemaMigrationService;
19
20 /**
21 * Test case
22 */
23 class SqlSchemaMigrationServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
24
25 /**
26 * Get a SchemaService instance with mocked DBAL enable database connection, DBAL not enabled
27 *
28 * @return \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface
29 */
30 protected function getSqlSchemaMigrationService() {
31 /** @var \TYPO3\CMS\Dbal\Database\DatabaseConnection|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $databaseConnection */
32 $subject = $this->getAccessibleMock(SqlSchemaMigrationService::class, array('isDbalEnabled'), array(), '', FALSE);
33 $subject->expects($this->any())->method('isDbalEnabled')->will($this->returnValue(FALSE));
34
35 return $subject;
36 }
37
38 /**
39 * Get a SchemaService instance with mocked DBAL enable database connection, DBAL enabled
40 *
41 * @return \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface
42 */
43 protected function getDbalEnabledSqlSchemaMigrationService() {
44 /** @var \TYPO3\CMS\Dbal\Database\DatabaseConnection|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $databaseConnection */
45 $databaseConnection = $this->getAccessibleMock(\TYPO3\CMS\Dbal\Database\DatabaseConnection::class, array('dummy'), array(), '', FALSE);
46 $databaseConnection->_set('dbmsSpecifics', GeneralUtility::makeInstance(\TYPO3\CMS\Dbal\Database\Specifics\PostgresSpecifics::class));
47
48 $subject = $this->getAccessibleMock(SqlSchemaMigrationService::class, array('isDbalEnabled', 'getDatabaseConnection'), array(), '', FALSE);
49 $subject->expects($this->any())->method('isDbalEnabled')->will($this->returnValue(TRUE));
50 $subject->expects($this->any())->method('getDatabaseConnection')->will($this->returnValue($databaseConnection));
51
52 return $subject;
53 }
54
55 /**
56 * @test
57 */
58 public function getFieldDefinitionsFileContentHandlesMultipleWhitespacesInFieldDefinitions() {
59 $subject = $this->getSqlSchemaMigrationService();
60 // Multiple whitespaces and tabs in field definition
61 $inputString = 'CREATE table atable (' . LF . 'aFieldName int(11)' . TAB . TAB . TAB . 'unsigned DEFAULT \'0\'' . LF . ');';
62 $result = $subject->getFieldDefinitions_fileContent($inputString);
63
64 $this->assertEquals(
65 array(
66 'atable' => array(
67 'fields' => array(
68 'aFieldName' => 'int(11) unsigned default \'0\'',
69 ),
70 'extra' => array(
71 'COLLATE' => '',
72 ),
73 ),
74 ),
75 $result
76 );
77 }
78
79 /**
80 * @test
81 */
82 public function getDatabaseExtraFindsChangedFields() {
83 $subject = $this->getSqlSchemaMigrationService();
84 $differenceArray = $subject->getDatabaseExtra(
85 array(
86 'tx_foo' => array(
87 'fields' => array(
88 'foo' => 'varchar(999) DEFAULT \'0\' NOT NULL'
89 )
90 )
91 ),
92 array(
93 'tx_foo' => array(
94 'fields' => array(
95 'foo' => 'varchar(255) DEFAULT \'0\' NOT NULL'
96 )
97 )
98 )
99 );
100
101 $this->assertEquals(
102 $differenceArray,
103 array(
104 'extra' => array(),
105 'diff' => array(
106 'tx_foo' => array(
107 'fields' => array(
108 'foo' => 'varchar(999) DEFAULT \'0\' NOT NULL'
109 )
110 )
111 ),
112 'diff_currentValues' => array(
113 'tx_foo' => array(
114 'fields' => array(
115 'foo' => 'varchar(255) DEFAULT \'0\' NOT NULL'
116 )
117 )
118 )
119 )
120 );
121 }
122
123 /**
124 * @test
125 */
126 public function getDatabaseExtraFindsChangedFieldsIncludingNull() {
127 $subject = $this->getSqlSchemaMigrationService();
128 $differenceArray = $subject->getDatabaseExtra(
129 array(
130 'tx_foo' => array(
131 'fields' => array(
132 'foo' => 'varchar(999) NULL'
133 )
134 )
135 ),
136 array(
137 'tx_foo' => array(
138 'fields' => array(
139 'foo' => 'varchar(255) NULL'
140 )
141 )
142 )
143 );
144
145 $this->assertEquals(
146 $differenceArray,
147 array(
148 'extra' => array(),
149 'diff' => array(
150 'tx_foo' => array(
151 'fields' => array(
152 'foo' => 'varchar(999) NULL'
153 )
154 )
155 ),
156 'diff_currentValues' => array(
157 'tx_foo' => array(
158 'fields' => array(
159 'foo' => 'varchar(255) NULL'
160 )
161 )
162 )
163 )
164 );
165 }
166
167 /**
168 * @test
169 */
170 public function getDatabaseExtraFindsChangedFieldsIgnoreNotNull() {
171 $subject = $this->getSqlSchemaMigrationService();
172 $differenceArray = $subject->getDatabaseExtra(
173 array(
174 'tx_foo' => array(
175 'fields' => array(
176 'foo' => 'varchar(999) DEFAULT \'0\' NOT NULL'
177 )
178 )
179 ),
180 array(
181 'tx_foo' => array(
182 'fields' => array(
183 'foo' => 'varchar(255) DEFAULT \'0\' NOT NULL'
184 )
185 )
186 ),
187 '',
188 TRUE
189 );
190
191 $this->assertEquals(
192 $differenceArray,
193 array(
194 'extra' => array(),
195 'diff' => array(
196 'tx_foo' => array(
197 'fields' => array(
198 'foo' => 'varchar(999) DEFAULT \'0\''
199 )
200 )
201 ),
202 'diff_currentValues' => array(
203 'tx_foo' => array(
204 'fields' => array(
205 'foo' => 'varchar(255) DEFAULT \'0\''
206 )
207 )
208 )
209 )
210 );
211 }
212
213 /**
214 * @test
215 */
216 public function getDatabaseExtraIgnoresCaseDifference() {
217 $subject = $this->getSqlSchemaMigrationService();
218 $differenceArray = $subject->getDatabaseExtra(
219 array(
220 'tx_foo' => array(
221 'fields' => array(
222 'foo' => 'INT(11) DEFAULT \'0\' NOT NULL',
223 )
224 )
225 ),
226 array(
227 'tx_foo' => array(
228 'fields' => array(
229 'foo' => 'int(11) DEFAULT \'0\' NOT NULL',
230 )
231 )
232 )
233 );
234
235
236 $this->assertEquals(
237 $differenceArray,
238 array(
239 'extra' => array(),
240 'diff' => array(),
241 'diff_currentValues' => NULL,
242 )
243 );
244 }
245
246 /**
247 * @test
248 */
249 public function getDatabaseExtraIgnoresCaseDifferenceButKeepsCaseInSetIntact() {
250 $subject = $this->getSqlSchemaMigrationService();
251 $differenceArray = $subject->getDatabaseExtra(
252 array(
253 'tx_foo' => array(
254 'fields' => array(
255 'subtype' => 'SET(\'Tx_MyExt_Domain_Model_Xyz\',\'Tx_MyExt_Domain_Model_Abc\',\'\') NOT NULL DEFAULT \'\',',
256 )
257 )
258 ),
259 array(
260 'tx_foo' => array(
261 'fields' => array(
262 'subtype' => 'set(\'Tx_MyExt_Domain_Model_Xyz\',\'Tx_MyExt_Domain_Model_Abc\',\'\') NOT NULL DEFAULT \'\',',
263 )
264 )
265 )
266 );
267
268 $this->assertEquals(
269 $differenceArray,
270 array(
271 'extra' => array(),
272 'diff' => array(),
273 'diff_currentValues' => NULL,
274 )
275 );
276 }
277
278 /**
279 * @test
280 */
281 public function getDatabaseExtraDoesNotLowercaseReservedWordsForTheComparison() {
282 $subject = $this->getSqlSchemaMigrationService();
283 $differenceArray = $subject->getDatabaseExtra(
284 array(
285 'tx_foo' => array(
286 'fields' => array(
287 'PRIMARY KEY (md5hash)',
288 )
289 )
290 ),
291 array(
292 'tx_foo' => array(
293 'fields' => array(
294 'PRIMARY KEY (md5hash)'),
295 )
296 )
297 );
298
299
300 $this->assertEquals(
301 $differenceArray,
302 array(
303 'extra' => array(),
304 'diff' => array(),
305 'diff_currentValues' => NULL,
306 )
307 );
308 }
309
310 /**
311 * @test
312 */
313 public function getDatabaseExtraFindsNewSpatialKeys() {
314 $subject = $this->getSqlSchemaMigrationService();
315 $differenceArray = $subject->getDatabaseExtra(
316 array(
317 'tx_foo' => array(
318 'keys' => array(
319 'foo' => 'SPATIAL foo (foo)'
320 )
321 )
322 ),
323 array(
324 'tx_foo' => array(
325 'keys' => array()
326 )
327 )
328 );
329
330 $this->assertEquals(
331 $differenceArray,
332 array(
333 'extra' => array(
334 'tx_foo' => array(
335 'keys' => array(
336 'foo' => 'SPATIAL foo (foo)'
337 )
338 )
339 ),
340 'diff' => array(),
341 'diff_currentValues' => NULL
342 )
343 );
344 }
345
346 /**
347 * @test
348 */
349 public function checkColumnDefinitionIfCommentIsSupplied() {
350 $subject = $this->getSqlSchemaMigrationService();
351 $fieldDefinition = $subject->assembleFieldDefinition(
352 array(
353 'Field' => 'uid',
354 'Type' => 'int(11)',
355 'Null' => 'NO',
356 'Key' => 'PRI',
357 'Default' => NULL,
358 'Extra' => 'auto_increment',
359 'Comment' => 'I am a comment',
360 )
361 );
362
363
364 $this->assertSame(
365 'int(11) NOT NULL auto_increment COMMENT \'I am a comment\'',
366 $fieldDefinition
367 );
368 }
369
370 /**
371 * @test
372 */
373 public function checkColumnDefinitionIfNoCommentIsSupplied() {
374 $subject = $this->getSqlSchemaMigrationService();
375 $fieldDefinition = $subject->assembleFieldDefinition(
376 array(
377 'Field' => 'uid',
378 'Type' => 'int(11)',
379 'Null' => 'NO',
380 'Key' => 'PRI',
381 'Default' => NULL,
382 'Extra' => 'auto_increment',
383 )
384 );
385
386
387 $this->assertSame(
388 'int(11) NOT NULL auto_increment',
389 $fieldDefinition
390 );
391 }
392
393 /**
394 * @test
395 */
396 public function getDatabaseExtraIncludesEngineIfMySQLIsUsed() {
397 $subject = $this->getSqlSchemaMigrationService();
398 $differenceArray = $subject->getDatabaseExtra(
399 array(
400 'tx_foo' => array(
401 'fields' => array(
402 'foo' => 'INT(11) DEFAULT \'0\' NOT NULL',
403 ),
404 'extra' => array(
405 'ENGINE' => 'InnoDB'
406 )
407 )
408 ),
409 array(
410 'tx_foo' => array(
411 'fields' => array(
412 'foo' => 'int(11) DEFAULT \'0\' NOT NULL',
413 ),
414 'extra' => array(
415 'ENGINE' => 'InnoDB'
416 )
417 )
418 )
419 );
420
421 $this->assertSame(
422 $differenceArray,
423 array(
424 'extra' => array(),
425 'diff' => array(),
426 'diff_currentValues' => NULL,
427 )
428 );
429 }
430
431 /**
432 * @test
433 */
434 public function getDatabaseExtraExcludesEngineIfDbalIsUsed() {
435 $subject = $this->getDbalEnabledSqlSchemaMigrationService();
436 $differenceArray = $subject->getDatabaseExtra(
437 array(
438 'tx_foo' => array(
439 'fields' => array(
440 'foo' => 'INT(11) DEFAULT \'0\' NOT NULL',
441 ),
442 'extra' => array(
443 'ENGINE' => 'InnoDB'
444 )
445 )
446 ),
447 array(
448 'tx_foo' => array(
449 'fields' => array(
450 'foo' => 'int(11) DEFAULT \'0\' NOT NULL',
451 ),
452 'extra' => array()
453 )
454 )
455 );
456
457 $this->assertSame(
458 $differenceArray,
459 array(
460 'extra' => array(),
461 'diff' => array(),
462 'diff_currentValues' => NULL,
463 )
464 );
465 }
466
467 /**
468 * @test
469 */
470 public function getDatabaseExtraIncludesUnsignedAttributeIfMySQLIsUsed() {
471 $subject = $this->getSqlSchemaMigrationService();
472 $differenceArray = $subject->getDatabaseExtra(
473 array(
474 'tx_foo' => array(
475 'fields' => array(
476 'foo' => 'INT(11) UNSIGNED DEFAULT \'0\' NOT NULL',
477 ),
478 'extra' => array(
479 'ENGINE' => 'InnoDB'
480 )
481 )
482 ),
483 array(
484 'tx_foo' => array(
485 'fields' => array(
486 'foo' => 'int(11) DEFAULT \'0\' NOT NULL',
487 ),
488 'extra' => array(
489 'ENGINE' => 'InnoDB'
490 )
491 )
492 )
493 );
494
495 $this->assertSame(
496 $differenceArray,
497 array(
498 'extra' => array(),
499 'diff' => array(
500 'tx_foo' => array(
501 'fields' => array(
502 'foo' => 'int(11) UNSIGNED DEFAULT \'0\' NOT NULL',
503 ),
504 )
505 ),
506 'diff_currentValues' => array(
507 'tx_foo' => array(
508 'fields' => array(
509 'foo' => 'int(11) DEFAULT \'0\' NOT NULL',
510 ),
511 )
512 )
513 )
514 );
515 }
516
517 /**
518 * @test
519 */
520 public function getDatabaseExtraExcludesUnsignedAttributeIfDbalIsUsed() {
521 $subject = $this->getDbalEnabledSqlSchemaMigrationService();
522 $differenceArray = $subject->getDatabaseExtra(
523 array(
524 'tx_foo' => array(
525 'fields' => array(
526 'foo' => 'INT(11) UNSIGNED DEFAULT \'0\' NOT NULL',
527 ),
528 'extra' => array(
529 'ENGINE' => 'InnoDB'
530 )
531 )
532 ),
533 array(
534 'tx_foo' => array(
535 'fields' => array(
536 'foo' => 'int(11) DEFAULT \'0\' NOT NULL',
537 ),
538 'extra' => array(
539 'ENGINE' => 'InnoDB'
540 )
541 )
542 )
543 );
544
545 $this->assertSame(
546 $differenceArray,
547 array(
548 'extra' => array(),
549 'diff' => array(),
550 'diff_currentValues' => NULL
551 )
552 );
553 }
554
555 /**
556 * @test
557 */
558 public function getDatabaseExtraIgnoresIndexPrefixLengthIfDbalIsUsed() {
559 $subject = $this->getDbalEnabledSqlSchemaMigrationService();
560 $differenceArray = $subject->getDatabaseExtra(
561 array(
562 'tx_foo' => array(
563 'keys' => array(
564 'foo' => 'KEY foo (foo(199))'
565 )
566 )
567 ),
568 array(
569 'tx_foo' => array(
570 'keys' => array(
571 'foo' => 'KEY foo (foo)'
572 )
573 )
574 )
575 );
576
577 $this->assertSame(
578 $differenceArray,
579 array(
580 'extra' => array(),
581 'diff' => array(),
582 'diff_currentValues' => NULL,
583 )
584 );
585 }
586
587 /**
588 * @test
589 */
590 public function getDatabaseExtraComparesIndexPrefixLengthIfMySQLIsUsed() {
591 $subject = $this->getSqlSchemaMigrationService();
592 $differenceArray = $subject->getDatabaseExtra(
593 array(
594 'tx_foo' => array(
595 'keys' => array(
596 'foo' => 'KEY foo (foo(199))'
597 )
598 )
599 ),
600 array(
601 'tx_foo' => array(
602 'keys' => array(
603 'foo' => 'KEY foo (foo)'
604 )
605 )
606 )
607 );
608
609 $this->assertSame(
610 $differenceArray,
611 array(
612 'extra' => array(),
613 'diff' => array(
614 'tx_foo' => array(
615 'keys' => array(
616 'foo' => 'KEY foo (foo(199))'
617 )
618 )
619 ),
620 'diff_currentValues' => array(
621 'tx_foo' => array(
622 'keys' => array(
623 'foo' => 'KEY foo (foo)'
624 )
625 )
626 )
627 )
628 );
629 }
630 }