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