Failed Conditions
Push — master ( 30b923...92920e )
by Marco
19s queued 13s
created

Doctrine/Tests/DBAL/Schema/ComparatorTest.php (1 issue)

1
<?php
2
3
namespace Doctrine\Tests\DBAL\Schema;
4
5
use Doctrine\DBAL\Schema\Column;
6
use Doctrine\DBAL\Schema\ColumnDiff;
7
use Doctrine\DBAL\Schema\Comparator;
8
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
9
use Doctrine\DBAL\Schema\Index;
10
use Doctrine\DBAL\Schema\Schema;
11
use Doctrine\DBAL\Schema\SchemaConfig;
12
use Doctrine\DBAL\Schema\SchemaDiff;
13
use Doctrine\DBAL\Schema\Sequence;
14
use Doctrine\DBAL\Schema\Table;
15
use Doctrine\DBAL\Schema\TableDiff;
16
use Doctrine\DBAL\Types\Type;
17
use PHPUnit\Framework\TestCase;
18
use function array_keys;
19
20
class ComparatorTest extends TestCase
21
{
22
    public function testCompareSame1()
23
    {
24
        $schema1 = new Schema([
25
            'bugdb' => new Table(
26
                'bugdb',
27
                [
28
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
29
                ]
30
            ),
31
        ]);
32
        $schema2 = new Schema([
33
            'bugdb' => new Table(
34
                'bugdb',
35
                [
36
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
37
                ]
38
            ),
39
        ]);
40
41
        $expected             = new SchemaDiff();
42
        $expected->fromSchema = $schema1;
43
        self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
44
    }
45
46
    public function testCompareSame2()
47
    {
48
        $schema1 = new Schema([
49
            'bugdb' => new Table(
50
                'bugdb',
51
                [
52
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
53
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
54
                ]
55
            ),
56
        ]);
57
        $schema2 = new Schema([
58
            'bugdb' => new Table(
59
                'bugdb',
60
                [
61
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
62
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
63
                ]
64
            ),
65
        ]);
66
67
        $expected             = new SchemaDiff();
68
        $expected->fromSchema = $schema1;
69
        self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
70
    }
71
72
    public function testCompareMissingTable()
73
    {
74
        $schemaConfig = new SchemaConfig();
75
        $table        = new Table('bugdb', ['integerfield1' => new Column('integerfield1', Type::getType('integer'))]);
76
        $table->setSchemaConfig($schemaConfig);
77
78
        $schema1 = new Schema([$table], [], $schemaConfig);
79
        $schema2 = new Schema([], [], $schemaConfig);
80
81
        $expected = new SchemaDiff([], [], ['bugdb' => $table], $schema1);
82
83
        self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
84
    }
85
86
    public function testCompareNewTable()
87
    {
88
        $schemaConfig = new SchemaConfig();
89
        $table        = new Table('bugdb', ['integerfield1' => new Column('integerfield1', Type::getType('integer'))]);
90
        $table->setSchemaConfig($schemaConfig);
91
92
        $schema1 = new Schema([], [], $schemaConfig);
93
        $schema2 = new Schema([$table], [], $schemaConfig);
94
95
        $expected = new SchemaDiff(['bugdb' => $table], [], [], $schema1);
96
97
        self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
98
    }
99
100
    public function testCompareOnlyAutoincrementChanged()
101
    {
102
        $column1 = new Column('foo', Type::getType('integer'), ['autoincrement' => true]);
103
        $column2 = new Column('foo', Type::getType('integer'), ['autoincrement' => false]);
104
105
        $comparator        = new Comparator();
106
        $changedProperties = $comparator->diffColumn($column1, $column2);
107
108
        self::assertEquals(['autoincrement'], $changedProperties);
109
    }
110
111
    public function testCompareMissingField()
112
    {
113
        $missingColumn = new Column('integerfield1', Type::getType('integer'));
114
        $schema1       = new Schema([
115
            'bugdb' => new Table(
116
                'bugdb',
117
                [
118
                    'integerfield1' => $missingColumn,
119
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
120
                ]
121
            ),
122
        ]);
123
        $schema2       = new Schema([
124
            'bugdb' => new Table(
125
                'bugdb',
126
                [
127
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
128
                ]
129
            ),
130
        ]);
131
132
        $expected                                    = new SchemaDiff(
133
            [],
134
            [
135
                'bugdb' => new TableDiff(
136
                    'bugdb',
137
                    [],
138
                    [],
139
                    ['integerfield1' => $missingColumn]
140
                ),
141
            ]
142
        );
143
        $expected->fromSchema                        = $schema1;
144
        $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
145
146
        self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
147
    }
148
149
    public function testCompareNewField()
150
    {
151
        $schema1 = new Schema([
152
            'bugdb' => new Table(
153
                'bugdb',
154
                [
155
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
156
                ]
157
            ),
158
        ]);
159
        $schema2 = new Schema([
160
            'bugdb' => new Table(
161
                'bugdb',
162
                [
163
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
164
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
165
                ]
166
            ),
167
        ]);
168
169
        $expected                                    = new SchemaDiff(
170
            [],
171
            [
172
                'bugdb' => new TableDiff(
173
                    'bugdb',
174
                    [
175
                        'integerfield2' => new Column('integerfield2', Type::getType('integer')),
176
                    ]
177
                ),
178
            ]
179
        );
180
        $expected->fromSchema                        = $schema1;
181
        $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
182
183
        self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
184
    }
185
186
    public function testCompareChangedColumnsChangeType()
187
    {
188
        $column1 = new Column('charfield1', Type::getType('string'));
189
        $column2 = new Column('charfield1', Type::getType('integer'));
190
191
        $c = new Comparator();
192
        self::assertEquals(['type'], $c->diffColumn($column1, $column2));
193
        self::assertEquals([], $c->diffColumn($column1, $column1));
194
    }
195
196
    public function testCompareChangedColumnsChangeCustomSchemaOption()
197
    {
198
        $column1 = new Column('charfield1', Type::getType('string'));
199
        $column2 = new Column('charfield1', Type::getType('string'));
200
201
        $column1->setCustomSchemaOption('foo', 'bar');
202
        $column2->setCustomSchemaOption('foo', 'bar');
203
204
        $column1->setCustomSchemaOption('foo1', 'bar1');
205
        $column2->setCustomSchemaOption('foo2', 'bar2');
206
207
        $c = new Comparator();
208
        self::assertEquals(['foo1', 'foo2'], $c->diffColumn($column1, $column2));
209
        self::assertEquals([], $c->diffColumn($column1, $column1));
210
    }
211
212
    public function testCompareChangeColumnsMultipleNewColumnsRename()
213
    {
214
        $tableA = new Table('foo');
215
        $tableA->addColumn('datefield1', 'datetime');
216
217
        $tableB = new Table('foo');
218
        $tableB->addColumn('new_datefield1', 'datetime');
219
        $tableB->addColumn('new_datefield2', 'datetime');
220
221
        $c         = new Comparator();
222
        $tableDiff = $c->diffTable($tableA, $tableB);
223
224
        self::assertCount(1, $tableDiff->renamedColumns, 'we should have one rename datefield1 => new_datefield1.');
225
        self::assertArrayHasKey('datefield1', $tableDiff->renamedColumns, "'datefield1' should be set to be renamed to new_datefield1");
226
        self::assertCount(1, $tableDiff->addedColumns, "'new_datefield2' should be added");
227
        self::assertArrayHasKey('new_datefield2', $tableDiff->addedColumns, "'new_datefield2' should be added, not created through renaming!");
228
        self::assertCount(0, $tableDiff->removedColumns, 'Nothing should be removed.');
229
        self::assertCount(0, $tableDiff->changedColumns, 'Nothing should be changed as all fields old & new have diff names.');
230
    }
231
232
    public function testCompareRemovedIndex()
233
    {
234
        $schema1 = new Schema([
235
            'bugdb' => new Table(
236
                'bugdb',
237
                [
238
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
239
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
240
                ],
241
                [
242
                    'primary' => new Index(
243
                        'primary',
244
                        ['integerfield1'],
245
                        true
246
                    ),
247
                ]
248
            ),
249
        ]);
250
        $schema2 = new Schema([
251
            'bugdb' => new Table(
252
                'bugdb',
253
                [
254
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
255
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
256
                ]
257
            ),
258
        ]);
259
260
        $expected                                    = new SchemaDiff(
261
            [],
262
            [
263
                'bugdb' => new TableDiff(
264
                    'bugdb',
265
                    [],
266
                    [],
267
                    [],
268
                    [],
269
                    [],
270
                    [
271
                        'primary' => new Index(
272
                            'primary',
273
                            ['integerfield1'],
274
                            true
275
                        ),
276
                    ]
277
                ),
278
            ]
279
        );
280
        $expected->fromSchema                        = $schema1;
281
        $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
282
283
        self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
284
    }
285
286
    public function testCompareNewIndex()
287
    {
288
        $schema1 = new Schema([
289
            'bugdb' => new Table(
290
                'bugdb',
291
                [
292
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
293
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
294
                ]
295
            ),
296
        ]);
297
        $schema2 = new Schema([
298
            'bugdb' => new Table(
299
                'bugdb',
300
                [
301
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
302
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
303
                ],
304
                [
305
                    'primary' => new Index(
306
                        'primary',
307
                        ['integerfield1'],
308
                        true
309
                    ),
310
                ]
311
            ),
312
        ]);
313
314
        $expected                                    = new SchemaDiff(
315
            [],
316
            [
317
                'bugdb' => new TableDiff(
318
                    'bugdb',
319
                    [],
320
                    [],
321
                    [],
322
                    [
323
                        'primary' => new Index(
324
                            'primary',
325
                            ['integerfield1'],
326
                            true
327
                        ),
328
                    ]
329
                ),
330
            ]
331
        );
332
        $expected->fromSchema                        = $schema1;
333
        $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
334
335
        self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
336
    }
337
338
    public function testCompareChangedIndex()
339
    {
340
        $schema1 = new Schema([
341
            'bugdb' => new Table(
342
                'bugdb',
343
                [
344
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
345
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
346
                ],
347
                [
348
                    'primary' => new Index(
349
                        'primary',
350
                        ['integerfield1'],
351
                        true
352
                    ),
353
                ]
354
            ),
355
        ]);
356
        $schema2 = new Schema([
357
            'bugdb' => new Table(
358
                'bugdb',
359
                [
360
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
361
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
362
                ],
363
                [
364
                    'primary' => new Index(
365
                        'primary',
366
                        ['integerfield1', 'integerfield2'],
367
                        true
368
                    ),
369
                ]
370
            ),
371
        ]);
372
373
        $expected                                    = new SchemaDiff(
374
            [],
375
            [
376
                'bugdb' => new TableDiff(
377
                    'bugdb',
378
                    [],
379
                    [],
380
                    [],
381
                    [],
382
                    [
383
                        'primary' => new Index(
384
                            'primary',
385
                            [
386
                                'integerfield1',
387
                                'integerfield2',
388
                            ],
389
                            true
390
                        ),
391
                    ]
392
                ),
393
            ]
394
        );
395
        $expected->fromSchema                        = $schema1;
396
        $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
397
398
        self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
399
    }
400
401
    public function testCompareChangedIndexFieldPositions()
402
    {
403
        $schema1 = new Schema([
404
            'bugdb' => new Table(
405
                'bugdb',
406
                [
407
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
408
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
409
                ],
410
                [
411
                    'primary' => new Index('primary', ['integerfield1', 'integerfield2'], true),
412
                ]
413
            ),
414
        ]);
415
        $schema2 = new Schema([
416
            'bugdb' => new Table(
417
                'bugdb',
418
                [
419
                    'integerfield1' => new Column('integerfield1', Type::getType('integer')),
420
                    'integerfield2' => new Column('integerfield2', Type::getType('integer')),
421
                ],
422
                [
423
                    'primary' => new Index('primary', ['integerfield2', 'integerfield1'], true),
424
                ]
425
            ),
426
        ]);
427
428
        $expected                                    = new SchemaDiff(
429
            [],
430
            [
431
                'bugdb' => new TableDiff(
432
                    'bugdb',
433
                    [],
434
                    [],
435
                    [],
436
                    [],
437
                    [
438
                        'primary' => new Index('primary', ['integerfield2', 'integerfield1'], true),
439
                    ]
440
                ),
441
            ]
442
        );
443
        $expected->fromSchema                        = $schema1;
444
        $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb');
445
446
        self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2));
447
    }
448
449
    public function testCompareSequences()
450
    {
451
        $seq1 = new Sequence('foo', 1, 1);
452
        $seq2 = new Sequence('foo', 1, 2);
453
        $seq3 = new Sequence('foo', 2, 1);
454
        $seq4 = new Sequence('foo', '1', '1');
455
456
        $c = new Comparator();
457
458
        self::assertTrue($c->diffSequence($seq1, $seq2));
459
        self::assertTrue($c->diffSequence($seq1, $seq3));
460
        self::assertFalse($c->diffSequence($seq1, $seq4));
461
    }
462
463
    public function testRemovedSequence()
464
    {
465
        $schema1 = new Schema();
466
        $seq     = $schema1->createSequence('foo');
467
468
        $schema2 = new Schema();
469
470
        $c          = new Comparator();
471
        $diffSchema = $c->compare($schema1, $schema2);
472
473
        self::assertCount(1, $diffSchema->removedSequences);
474
        self::assertSame($seq, $diffSchema->removedSequences[0]);
475
    }
476
477
    public function testAddedSequence()
478
    {
479
        $schema1 = new Schema();
480
481
        $schema2 = new Schema();
482
        $seq     = $schema2->createSequence('foo');
483
484
        $c          = new Comparator();
485
        $diffSchema = $c->compare($schema1, $schema2);
486
487
        self::assertCount(1, $diffSchema->newSequences);
488
        self::assertSame($seq, $diffSchema->newSequences[0]);
489
    }
490
491
    public function testTableAddForeignKey()
492
    {
493
        $tableForeign = new Table('bar');
494
        $tableForeign->addColumn('id', 'integer');
495
496
        $table1 = new Table('foo');
497
        $table1->addColumn('fk', 'integer');
498
499
        $table2 = new Table('foo');
500
        $table2->addColumn('fk', 'integer');
501
        $table2->addForeignKeyConstraint($tableForeign, ['fk'], ['id']);
502
503
        $c         = new Comparator();
504
        $tableDiff = $c->diffTable($table1, $table2);
505
506
        self::assertInstanceOf(TableDiff::class, $tableDiff);
507
        self::assertCount(1, $tableDiff->addedForeignKeys);
508
    }
509
510
    public function testTableRemoveForeignKey()
511
    {
512
        $tableForeign = new Table('bar');
513
        $tableForeign->addColumn('id', 'integer');
514
515
        $table1 = new Table('foo');
516
        $table1->addColumn('fk', 'integer');
517
518
        $table2 = new Table('foo');
519
        $table2->addColumn('fk', 'integer');
520
        $table2->addForeignKeyConstraint($tableForeign, ['fk'], ['id']);
521
522
        $c         = new Comparator();
523
        $tableDiff = $c->diffTable($table2, $table1);
524
525
        self::assertInstanceOf(TableDiff::class, $tableDiff);
526
        self::assertCount(1, $tableDiff->removedForeignKeys);
527
    }
528
529
    public function testTableUpdateForeignKey()
530
    {
531
        $tableForeign = new Table('bar');
532
        $tableForeign->addColumn('id', 'integer');
533
534
        $table1 = new Table('foo');
535
        $table1->addColumn('fk', 'integer');
536
        $table1->addForeignKeyConstraint($tableForeign, ['fk'], ['id']);
537
538
        $table2 = new Table('foo');
539
        $table2->addColumn('fk', 'integer');
540
        $table2->addForeignKeyConstraint($tableForeign, ['fk'], ['id'], ['onUpdate' => 'CASCADE']);
541
542
        $c         = new Comparator();
543
        $tableDiff = $c->diffTable($table1, $table2);
544
545
        self::assertInstanceOf(TableDiff::class, $tableDiff);
546
        self::assertCount(1, $tableDiff->changedForeignKeys);
547
    }
548
549
    public function testMovedForeignKeyForeignTable()
550
    {
551
        $tableForeign = new Table('bar');
552
        $tableForeign->addColumn('id', 'integer');
553
554
        $tableForeign2 = new Table('bar2');
555
        $tableForeign2->addColumn('id', 'integer');
556
557
        $table1 = new Table('foo');
558
        $table1->addColumn('fk', 'integer');
559
        $table1->addForeignKeyConstraint($tableForeign, ['fk'], ['id']);
560
561
        $table2 = new Table('foo');
562
        $table2->addColumn('fk', 'integer');
563
        $table2->addForeignKeyConstraint($tableForeign2, ['fk'], ['id']);
564
565
        $c         = new Comparator();
566
        $tableDiff = $c->diffTable($table1, $table2);
567
568
        self::assertInstanceOf(TableDiff::class, $tableDiff);
569
        self::assertCount(1, $tableDiff->changedForeignKeys);
570
    }
571
572
    public function testTablesCaseInsensitive()
573
    {
574
        $schemaA = new Schema();
575
        $schemaA->createTable('foo');
576
        $schemaA->createTable('bAr');
577
        $schemaA->createTable('BAZ');
578
        $schemaA->createTable('new');
579
580
        $schemaB = new Schema();
581
        $schemaB->createTable('FOO');
582
        $schemaB->createTable('bar');
583
        $schemaB->createTable('Baz');
584
        $schemaB->createTable('old');
585
586
        $c    = new Comparator();
587
        $diff = $c->compare($schemaA, $schemaB);
588
589
        self::assertSchemaTableChangeCount($diff, 1, 0, 1);
590
    }
591
592
    public function testSequencesCaseInsensitive()
593
    {
594
        $schemaA = new Schema();
595
        $schemaA->createSequence('foo');
596
        $schemaA->createSequence('BAR');
597
        $schemaA->createSequence('Baz');
598
        $schemaA->createSequence('new');
599
600
        $schemaB = new Schema();
601
        $schemaB->createSequence('FOO');
602
        $schemaB->createSequence('Bar');
603
        $schemaB->createSequence('baz');
604
        $schemaB->createSequence('old');
605
606
        $c    = new Comparator();
607
        $diff = $c->compare($schemaA, $schemaB);
608
609
        self::assertSchemaSequenceChangeCount($diff, 1, 0, 1);
610
    }
611
612
    public function testCompareColumnCompareCaseInsensitive()
613
    {
614
        $tableA = new Table('foo');
615
        $tableA->addColumn('id', 'integer');
616
617
        $tableB = new Table('foo');
618
        $tableB->addColumn('ID', 'integer');
619
620
        $c         = new Comparator();
621
        $tableDiff = $c->diffTable($tableA, $tableB);
622
623
        self::assertFalse($tableDiff);
624
    }
625
626
    public function testCompareIndexBasedOnPropertiesNotName()
627
    {
628
        $tableA = new Table('foo');
629
        $tableA->addColumn('id', 'integer');
630
        $tableA->addIndex(['id'], 'foo_bar_idx');
631
632
        $tableB = new Table('foo');
633
        $tableB->addColumn('ID', 'integer');
634
        $tableB->addIndex(['id'], 'bar_foo_idx');
635
636
        $c                                        = new Comparator();
637
        $tableDiff                                = new TableDiff('foo');
638
        $tableDiff->fromTable                     = $tableA;
639
        $tableDiff->renamedIndexes['foo_bar_idx'] = new Index('bar_foo_idx', ['id']);
640
641
        self::assertEquals(
642
            $tableDiff,
643
            $c->diffTable($tableA, $tableB)
644
        );
645
    }
646
647
    public function testCompareForeignKeyBasedOnPropertiesNotName()
648
    {
649
        $tableA = new Table('foo');
650
        $tableA->addColumn('id', 'integer');
651
        $tableA->addNamedForeignKeyConstraint('foo_constraint', 'bar', ['id'], ['id']);
652
653
        $tableB = new Table('foo');
654
        $tableB->addColumn('ID', 'integer');
655
        $tableB->addNamedForeignKeyConstraint('bar_constraint', 'bar', ['id'], ['id']);
656
657
        $c         = new Comparator();
658
        $tableDiff = $c->diffTable($tableA, $tableB);
659
660
        self::assertFalse($tableDiff);
661
    }
662
663
    public function testCompareForeignKeyRestrictNoActionAreTheSame()
664
    {
665
        $fk1 = new ForeignKeyConstraint(['foo'], 'bar', ['baz'], 'fk1', ['onDelete' => 'NO ACTION']);
666
        $fk2 = new ForeignKeyConstraint(['foo'], 'bar', ['baz'], 'fk1', ['onDelete' => 'RESTRICT']);
667
668
        $c = new Comparator();
669
        self::assertFalse($c->diffForeignKey($fk1, $fk2));
670
    }
671
672
    /**
673
     * @group DBAL-492
674
     */
675
    public function testCompareForeignKeyNamesUnqualifiedAsNoSchemaInformationIsAvailable()
676
    {
677
        $fk1 = new ForeignKeyConstraint(['foo'], 'foo.bar', ['baz'], 'fk1');
678
        $fk2 = new ForeignKeyConstraint(['foo'], 'baz.bar', ['baz'], 'fk1');
679
680
        $c = new Comparator();
681
        self::assertFalse($c->diffForeignKey($fk1, $fk2));
682
    }
683
684
    public function testDetectRenameColumn()
685
    {
686
        $tableA = new Table('foo');
687
        $tableA->addColumn('foo', 'integer');
688
689
        $tableB = new Table('foo');
690
        $tableB->addColumn('bar', 'integer');
691
692
        $c         = new Comparator();
693
        $tableDiff = $c->diffTable($tableA, $tableB);
694
695
        self::assertCount(0, $tableDiff->addedColumns);
696
        self::assertCount(0, $tableDiff->removedColumns);
697
        self::assertArrayHasKey('foo', $tableDiff->renamedColumns);
698
        self::assertEquals('bar', $tableDiff->renamedColumns['foo']->getName());
699
    }
700
701
    /**
702
     * You can easily have ambiguities in the column renaming. If these
703
     * are detected no renaming should take place, instead adding and dropping
704
     * should be used exclusively.
705
     *
706
     * @group DBAL-24
707
     */
708
    public function testDetectRenameColumnAmbiguous()
709
    {
710
        $tableA = new Table('foo');
711
        $tableA->addColumn('foo', 'integer');
712
        $tableA->addColumn('bar', 'integer');
713
714
        $tableB = new Table('foo');
715
        $tableB->addColumn('baz', 'integer');
716
717
        $c         = new Comparator();
718
        $tableDiff = $c->diffTable($tableA, $tableB);
719
720
        self::assertCount(1, $tableDiff->addedColumns, "'baz' should be added, not created through renaming!");
721
        self::assertArrayHasKey('baz', $tableDiff->addedColumns, "'baz' should be added, not created through renaming!");
722
        self::assertCount(2, $tableDiff->removedColumns, "'foo' and 'bar' should both be dropped, an ambiguity exists which one could be renamed to 'baz'.");
723
        self::assertArrayHasKey('foo', $tableDiff->removedColumns, "'foo' should be removed.");
724
        self::assertArrayHasKey('bar', $tableDiff->removedColumns, "'bar' should be removed.");
725
        self::assertCount(0, $tableDiff->renamedColumns, 'no renamings should take place.');
726
    }
727
728
    /**
729
     * @group DBAL-1063
730
     */
731
    public function testDetectRenameIndex()
732
    {
733
        $table1 = new Table('foo');
734
        $table1->addColumn('foo', 'integer');
735
736
        $table2 = clone $table1;
737
738
        $table1->addIndex(['foo'], 'idx_foo');
739
740
        $table2->addIndex(['foo'], 'idx_bar');
741
742
        $comparator = new Comparator();
743
        $tableDiff  = $comparator->diffTable($table1, $table2);
744
745
        self::assertCount(0, $tableDiff->addedIndexes);
746
        self::assertCount(0, $tableDiff->removedIndexes);
747
        self::assertArrayHasKey('idx_foo', $tableDiff->renamedIndexes);
748
        self::assertEquals('idx_bar', $tableDiff->renamedIndexes['idx_foo']->getName());
749
    }
750
751
    /**
752
     * You can easily have ambiguities in the index renaming. If these
753
     * are detected no renaming should take place, instead adding and dropping
754
     * should be used exclusively.
755
     *
756
     * @group DBAL-1063
757
     */
758
    public function testDetectRenameIndexAmbiguous()
759
    {
760
        $table1 = new Table('foo');
761
        $table1->addColumn('foo', 'integer');
762
763
        $table2 = clone $table1;
764
765
        $table1->addIndex(['foo'], 'idx_foo');
766
        $table1->addIndex(['foo'], 'idx_bar');
767
768
        $table2->addIndex(['foo'], 'idx_baz');
769
770
        $comparator = new Comparator();
771
        $tableDiff  = $comparator->diffTable($table1, $table2);
772
773
        self::assertCount(1, $tableDiff->addedIndexes);
774
        self::assertArrayHasKey('idx_baz', $tableDiff->addedIndexes);
775
        self::assertCount(2, $tableDiff->removedIndexes);
776
        self::assertArrayHasKey('idx_foo', $tableDiff->removedIndexes);
777
        self::assertArrayHasKey('idx_bar', $tableDiff->removedIndexes);
778
        self::assertCount(0, $tableDiff->renamedIndexes);
779
    }
780
781
    public function testDetectChangeIdentifierType()
782
    {
783
        $this->markTestSkipped('DBAL-2 was reopened, this test cannot work anymore.');
784
785
        $tableA = new Table('foo');
786
        $tableA->addColumn('id', 'integer', ['autoincrement' => false]);
787
788
        $tableB = new Table('foo');
789
        $tableB->addColumn('id', 'integer', ['autoincrement' => true]);
790
791
        $c         = new Comparator();
792
        $tableDiff = $c->diffTable($tableA, $tableB);
793
794
        self::assertInstanceOf(TableDiff::class, $tableDiff);
795
        self::assertArrayHasKey('id', $tableDiff->changedColumns);
796
    }
797
798
799
    /**
800
     * @group DBAL-105
801
     */
802
    public function testDiff()
803
    {
804
        $table = new Table('twitter_users');
805
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
806
        $table->addColumn('twitterId', 'integer');
807
        $table->addColumn('displayName', 'string');
808
        $table->setPrimaryKey(['id']);
809
810
        $newtable = new Table('twitter_users');
811
        $newtable->addColumn('id', 'integer', ['autoincrement' => true]);
812
        $newtable->addColumn('twitter_id', 'integer');
813
        $newtable->addColumn('display_name', 'string');
814
        $newtable->addColumn('logged_in_at', 'datetime');
815
        $newtable->setPrimaryKey(['id']);
816
817
        $c         = new Comparator();
818
        $tableDiff = $c->diffTable($table, $newtable);
819
820
        self::assertInstanceOf(TableDiff::class, $tableDiff);
821
        self::assertEquals(['twitterid', 'displayname'], array_keys($tableDiff->renamedColumns));
822
        self::assertEquals(['logged_in_at'], array_keys($tableDiff->addedColumns));
823
        self::assertCount(0, $tableDiff->removedColumns);
824
    }
825
826
827
    /**
828
     * @group DBAL-112
829
     */
830
    public function testChangedSequence()
831
    {
832
        $schema   = new Schema();
833
        $sequence = $schema->createSequence('baz');
834
835
        $schemaNew = clone $schema;
836
        $schemaNew->getSequence('baz')->setAllocationSize(20);
837
838
        $c    = new Comparator();
839
        $diff = $c->compare($schema, $schemaNew);
840
841
        self::assertSame($diff->changedSequences[0], $schemaNew->getSequence('baz'));
842
    }
843
844
    /**
845
     * @group DBAL-106
846
     */
847
    public function testDiffDecimalWithNullPrecision()
848
    {
849
        $column = new Column('foo', Type::getType('decimal'));
850
        $column->setPrecision(null);
851
852
        $column2 = new Column('foo', Type::getType('decimal'));
853
854
        $c = new Comparator();
855
        self::assertEquals([], $c->diffColumn($column, $column2));
856
    }
857
858
    /**
859
     * @group DBAL-204
860
     */
861
    public function testFqnSchemaComparison()
862
    {
863
        $config = new SchemaConfig();
864
        $config->setName('foo');
865
866
        $oldSchema = new Schema([], [], $config);
867
        $oldSchema->createTable('bar');
868
869
        $newSchema = new Schema([], [], $config);
870
        $newSchema->createTable('foo.bar');
871
872
        $expected             = new SchemaDiff();
873
        $expected->fromSchema = $oldSchema;
874
875
        self::assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema));
876
    }
877
878
    /**
879
     * @group DBAL-669
880
     */
881
    public function testNamespacesComparison()
882
    {
883
        $config = new SchemaConfig();
884
        $config->setName('schemaName');
885
886
        $oldSchema = new Schema([], [], $config);
887
        $oldSchema->createTable('taz');
888
        $oldSchema->createTable('war.tab');
889
890
        $newSchema = new Schema([], [], $config);
891
        $newSchema->createTable('bar.tab');
892
        $newSchema->createTable('baz.tab');
893
        $newSchema->createTable('war.tab');
894
895
        $expected                = new SchemaDiff();
896
        $expected->fromSchema    = $oldSchema;
897
        $expected->newNamespaces = ['bar' => 'bar', 'baz' => 'baz'];
898
899
        $diff = Comparator::compareSchemas($oldSchema, $newSchema);
900
901
        self::assertEquals(['bar' => 'bar', 'baz' => 'baz'], $diff->newNamespaces);
902
        self::assertCount(2, $diff->newTables);
903
    }
904
905
    /**
906
     * @group DBAL-204
907
     */
908
    public function testFqnSchemaComparisonDifferentSchemaNameButSameTableNoDiff()
909
    {
910
        $config = new SchemaConfig();
911
        $config->setName('foo');
912
913
        $oldSchema = new Schema([], [], $config);
914
        $oldSchema->createTable('foo.bar');
915
916
        $newSchema = new Schema();
917
        $newSchema->createTable('bar');
918
919
        $expected             = new SchemaDiff();
920
        $expected->fromSchema = $oldSchema;
921
922
        self::assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema));
923
    }
924
925
    /**
926
     * @group DBAL-204
927
     */
928
    public function testFqnSchemaComparisonNoSchemaSame()
929
    {
930
        $config = new SchemaConfig();
931
        $config->setName('foo');
932
        $oldSchema = new Schema([], [], $config);
933
        $oldSchema->createTable('bar');
934
935
        $newSchema = new Schema();
936
        $newSchema->createTable('bar');
937
938
        $expected             = new SchemaDiff();
939
        $expected->fromSchema = $oldSchema;
940
941
        self::assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema));
942
    }
943
944
    /**
945
     * @group DDC-1657
946
     */
947
    public function testAutoIncrementSequences()
948
    {
949
        $oldSchema = new Schema();
950
        $table     = $oldSchema->createTable('foo');
951
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
952
        $table->setPrimaryKey(['id']);
953
        $oldSchema->createSequence('foo_id_seq');
954
955
        $newSchema = new Schema();
956
        $table     = $newSchema->createTable('foo');
957
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
958
        $table->setPrimaryKey(['id']);
959
960
        $c    = new Comparator();
961
        $diff = $c->compare($oldSchema, $newSchema);
962
963
        self::assertCount(0, $diff->removedSequences);
964
    }
965
966
967
    /**
968
     * Check that added autoincrement sequence is not populated in newSequences
969
     *
970
     * @group DBAL-562
971
     */
972
    public function testAutoIncrementNoSequences()
973
    {
974
        $oldSchema = new Schema();
975
        $table     = $oldSchema->createTable('foo');
976
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
977
        $table->setPrimaryKey(['id']);
978
979
        $newSchema = new Schema();
980
        $table     = $newSchema->createTable('foo');
981
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
982
        $table->setPrimaryKey(['id']);
983
        $newSchema->createSequence('foo_id_seq');
984
985
        $c    = new Comparator();
986
        $diff = $c->compare($oldSchema, $newSchema);
987
988
        self::assertCount(0, $diff->newSequences);
989
    }
990
    /**
991
     * You can get multiple drops for a FK when a table referenced by a foreign
992
     * key is deleted, as this FK is referenced twice, once on the orphanedForeignKeys
993
     * array because of the dropped table, and once on changedTables array. We
994
     * now check that the key is present once.
995
     */
996
    public function testAvoidMultipleDropForeignKey()
997
    {
998
        $oldSchema = new Schema();
999
1000
        $tableA = $oldSchema->createTable('table_a');
1001
        $tableA->addColumn('id', 'integer');
1002
1003
        $tableB = $oldSchema->createTable('table_b');
1004
        $tableB->addColumn('id', 'integer');
1005
1006
        $tableC = $oldSchema->createTable('table_c');
1007
        $tableC->addColumn('id', 'integer');
1008
        $tableC->addColumn('table_a_id', 'integer');
1009
        $tableC->addColumn('table_b_id', 'integer');
1010
1011
        $tableC->addForeignKeyConstraint($tableA, ['table_a_id'], ['id']);
1012
        $tableC->addForeignKeyConstraint($tableB, ['table_b_id'], ['id']);
1013
1014
        $newSchema = new Schema();
1015
1016
        $tableB = $newSchema->createTable('table_b');
1017
        $tableB->addColumn('id', 'integer');
1018
1019
        $tableC = $newSchema->createTable('table_c');
1020
        $tableC->addColumn('id', 'integer');
1021
1022
        $comparator = new Comparator();
1023
        $schemaDiff = $comparator->compare($oldSchema, $newSchema);
1024
1025
        self::assertCount(1, $schemaDiff->changedTables['table_c']->removedForeignKeys);
1026
        self::assertCount(1, $schemaDiff->orphanedForeignKeys);
1027
    }
1028
1029
    public function testCompareChangedColumn()
1030
    {
1031
        $oldSchema = new Schema();
1032
1033
        $tableFoo = $oldSchema->createTable('foo');
1034
        $tableFoo->addColumn('id', 'integer');
1035
1036
        $newSchema = new Schema();
1037
        $table     = $newSchema->createTable('foo');
1038
        $table->addColumn('id', 'string');
1039
1040
        $expected                      = new SchemaDiff();
1041
        $expected->fromSchema          = $oldSchema;
1042
        $tableDiff                     = $expected->changedTables['foo'] = new TableDiff('foo');
1043
        $tableDiff->fromTable          = $tableFoo;
1044
        $columnDiff                    = $tableDiff->changedColumns['id'] = new ColumnDiff('id', $table->getColumn('id'));
1045
        $columnDiff->fromColumn        = $tableFoo->getColumn('id');
1046
        $columnDiff->changedProperties = ['type'];
1047
1048
        self::assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema));
1049
    }
1050
1051
    public function testCompareChangedBinaryColumn()
1052
    {
1053
        $oldSchema = new Schema();
1054
1055
        $tableFoo = $oldSchema->createTable('foo');
1056
        $tableFoo->addColumn('id', 'binary');
1057
1058
        $newSchema = new Schema();
1059
        $table     = $newSchema->createTable('foo');
1060
        $table->addColumn('id', 'binary', ['length' => 42, 'fixed' => true]);
1061
1062
        $expected                      = new SchemaDiff();
1063
        $expected->fromSchema          = $oldSchema;
1064
        $tableDiff                     = $expected->changedTables['foo'] = new TableDiff('foo');
1065
        $tableDiff->fromTable          = $tableFoo;
1066
        $columnDiff                    = $tableDiff->changedColumns['id'] = new ColumnDiff('id', $table->getColumn('id'));
1067
        $columnDiff->fromColumn        = $tableFoo->getColumn('id');
1068
        $columnDiff->changedProperties = ['length', 'fixed'];
1069
1070
        self::assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema));
1071
    }
1072
1073
    /**
1074
     * @group DBAL-617
1075
     */
1076
    public function testCompareQuotedAndUnquotedForeignKeyColumns()
1077
    {
1078
        $fk1 = new ForeignKeyConstraint(['foo'], 'bar', ['baz'], 'fk1', ['onDelete' => 'NO ACTION']);
1079
        $fk2 = new ForeignKeyConstraint(['`foo`'], 'bar', ['`baz`'], 'fk1', ['onDelete' => 'NO ACTION']);
1080
1081
        $comparator = new Comparator();
1082
        $diff       = $comparator->diffForeignKey($fk1, $fk2);
1083
1084
        self::assertFalse($diff);
1085
    }
1086
1087
    /**
1088
     * @param SchemaDiff $diff
1089
     * @param int        $newTableCount
1090
     * @param int        $changeTableCount
1091
     * @param int        $removeTableCount
1092
     */
1093
    public function assertSchemaTableChangeCount($diff, $newTableCount = 0, $changeTableCount = 0, $removeTableCount = 0)
1094
    {
1095
        self::assertCount($newTableCount, $diff->newTables);
1096
        self::assertCount($changeTableCount, $diff->changedTables);
1097
        self::assertCount($removeTableCount, $diff->removedTables);
1098
    }
1099
1100
    /**
1101
     * @param SchemaDiff $diff
1102
     * @param int        $newSequenceCount
1103
     * @param int        $changeSequenceCount
1104
     * @param int        $changeSequenceCount
1105
     */
1106
    public function assertSchemaSequenceChangeCount($diff, $newSequenceCount = 0, $changeSequenceCount = 0, $removeSequenceCount = 0)
1107
    {
1108
        self::assertCount($newSequenceCount, $diff->newSequences, 'Expected number of new sequences is wrong.');
1109
        self::assertCount($changeSequenceCount, $diff->changedSequences, 'Expected number of changed sequences is wrong.');
1110
        self::assertCount($removeSequenceCount, $diff->removedSequences, 'Expected number of removed sequences is wrong.');
1111
    }
1112
1113
    public function testDiffColumnPlatformOptions()
1114
    {
1115
        $column1 = new Column('foo', Type::getType('string'), ['platformOptions' => ['foo' => 'foo', 'bar' => 'bar']]);
1116
        $column2 = new Column('foo', Type::getType('string'), ['platformOptions' => ['foo' => 'foo', 'foobar' => 'foobar']]);
1117
        $column3 = new Column('foo', Type::getType('string'), ['platformOptions' => ['foo' => 'foo', 'bar' => 'rab']]);
1118
        $column4 = new Column('foo', Type::getType('string'));
1119
1120
        $comparator = new Comparator();
1121
1122
        self::assertEquals([], $comparator->diffColumn($column1, $column2));
1123
        self::assertEquals([], $comparator->diffColumn($column2, $column1));
1124
        self::assertEquals(['bar'], $comparator->diffColumn($column1, $column3));
1125
        self::assertEquals(['bar'], $comparator->diffColumn($column3, $column1));
1126
        self::assertEquals([], $comparator->diffColumn($column1, $column4));
1127
        self::assertEquals([], $comparator->diffColumn($column4, $column1));
1128
    }
1129
1130
    public function testComplexDiffColumn()
1131
    {
1132
        $column1 = new Column('foo', Type::getType('string'), [
1133
            'platformOptions' => ['foo' => 'foo'],
1134
            'customSchemaOptions' => ['foo' => 'bar'],
1135
        ]);
1136
1137
        $column2 = new Column('foo', Type::getType('string'), [
1138
            'platformOptions' => ['foo' => 'bar'],
1139
        ]);
1140
1141
        $comparator = new Comparator();
1142
1143
        self::assertEquals([], $comparator->diffColumn($column1, $column2));
1144
        self::assertEquals([], $comparator->diffColumn($column2, $column1));
1145
    }
1146
1147
    /**
1148
     * @group DBAL-669
1149
     */
1150
    public function testComparesNamespaces()
1151
    {
1152
        $comparator = new Comparator();
1153
        $fromSchema = $this->getMockBuilder(Schema::class)
1154
            ->setMethods(['getNamespaces', 'hasNamespace'])
1155
            ->getMock();
1156
        $toSchema   = $this->getMockBuilder(Schema::class)
1157
            ->setMethods(['getNamespaces', 'hasNamespace'])
1158
            ->getMock();
1159
1160
        $fromSchema->expects($this->once())
1161
            ->method('getNamespaces')
1162
            ->will($this->returnValue(['foo', 'bar']));
1163
1164
        $fromSchema->expects($this->at(0))
1165
            ->method('hasNamespace')
1166
            ->with('bar')
1167
            ->will($this->returnValue(true));
1168
1169
        $fromSchema->expects($this->at(1))
1170
            ->method('hasNamespace')
1171
            ->with('baz')
1172
            ->will($this->returnValue(false));
1173
1174
        $toSchema->expects($this->once())
1175
            ->method('getNamespaces')
1176
            ->will($this->returnValue(['bar', 'baz']));
1177
1178
        $toSchema->expects($this->at(1))
1179
            ->method('hasNamespace')
1180
            ->with('foo')
1181
            ->will($this->returnValue(false));
1182
1183
        $toSchema->expects($this->at(2))
1184
            ->method('hasNamespace')
1185
            ->with('bar')
1186
            ->will($this->returnValue(true));
1187
1188
        $expected                    = new SchemaDiff();
1189
        $expected->fromSchema        = $fromSchema;
1 ignored issue
show
Documentation Bug introduced by
It seems like $fromSchema of type PHPUnit\Framework\MockObject\MockObject is incompatible with the declared type Doctrine\DBAL\Schema\Schema|null of property $fromSchema.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1190
        $expected->newNamespaces     = ['baz' => 'baz'];
1191
        $expected->removedNamespaces = ['foo' => 'foo'];
1192
1193
        self::assertEquals($expected, $comparator->compare($fromSchema, $toSchema));
1194
    }
1195
1196
    public function testCompareGuidColumns()
1197
    {
1198
        $comparator = new Comparator();
1199
1200
        $column1 = new Column('foo', Type::getType('guid'), ['comment' => 'GUID 1']);
1201
        $column2 = new Column(
1202
            'foo',
1203
            Type::getType('guid'),
1204
            ['notnull' => false, 'length' => '36', 'fixed' => true, 'default' => 'NEWID()', 'comment' => 'GUID 2.']
1205
        );
1206
1207
        self::assertEquals(['notnull', 'default', 'comment'], $comparator->diffColumn($column1, $column2));
1208
        self::assertEquals(['notnull', 'default', 'comment'], $comparator->diffColumn($column2, $column1));
1209
    }
1210
1211
    /**
1212
     * @group DBAL-1009
1213
     * @dataProvider getCompareColumnComments
1214
     */
1215
    public function testCompareColumnComments($comment1, $comment2, $equals)
1216
    {
1217
        $column1 = new Column('foo', Type::getType('integer'), ['comment' => $comment1]);
1218
        $column2 = new Column('foo', Type::getType('integer'), ['comment' => $comment2]);
1219
1220
        $comparator = new Comparator();
1221
1222
        $expectedDiff = $equals ? [] : ['comment'];
1223
1224
        $actualDiff = $comparator->diffColumn($column1, $column2);
1225
1226
        self::assertSame($expectedDiff, $actualDiff);
1227
1228
        $actualDiff = $comparator->diffColumn($column2, $column1);
1229
1230
        self::assertSame($expectedDiff, $actualDiff);
1231
    }
1232
1233
    public function getCompareColumnComments()
1234
    {
1235
        return [
1236
            [null, null, true],
1237
            ['', '', true],
1238
            [' ', ' ', true],
1239
            ['0', '0', true],
1240
            ['foo', 'foo', true],
1241
1242
            [null, '', true],
1243
            [null, ' ', false],
1244
            [null, '0', false],
1245
            [null, 'foo', false],
1246
1247
            ['', ' ', false],
1248
            ['', '0', false],
1249
            ['', 'foo', false],
1250
1251
            [' ', '0', false],
1252
            [' ', 'foo', false],
1253
1254
            ['0', 'foo', false],
1255
        ];
1256
    }
1257
1258
    public function testForeignKeyRemovalWithRenamedLocalColumn()
1259
    {
1260
        $fromSchema = new Schema([
1261
            'table1' => new Table(
1262
                'table1',
1263
                [
1264
                    'id' => new Column('id', Type::getType('integer')),
1265
                ]
1266
            ),
1267
            'table2' => new Table(
1268
                'table2',
1269
                [
1270
                    'id' => new Column('id', Type::getType('integer')),
1271
                    'id_table1' => new Column('id_table1', Type::getType('integer')),
1272
                ],
1273
                [],
1274
                [
1275
                    new ForeignKeyConstraint(['id_table1'], 'table1', ['id'], 'fk_table2_table1'),
1276
                ]
1277
            ),
1278
        ]);
1279
        $toSchema   = new Schema([
1280
            'table2' => new Table(
1281
                'table2',
1282
                [
1283
                    'id' => new Column('id', Type::getType('integer')),
1284
                    'id_table3' => new Column('id_table3', Type::getType('integer')),
1285
                ],
1286
                [],
1287
                [
1288
                    new ForeignKeyConstraint(['id_table3'], 'table3', ['id'], 'fk_table2_table3'),
1289
                ]
1290
            ),
1291
            'table3' => new Table(
1292
                'table3',
1293
                [
1294
                    'id' => new Column('id', Type::getType('integer')),
1295
                ]
1296
            ),
1297
        ]);
1298
        $actual     = Comparator::compareSchemas($fromSchema, $toSchema);
1299
        self::assertArrayHasKey('table2', $actual->changedTables);
1300
        self::assertCount(1, $actual->orphanedForeignKeys);
1301
        self::assertEquals('fk_table2_table1', $actual->orphanedForeignKeys[0]->getName());
1302
        self::assertCount(1, $actual->changedTables['table2']->addedForeignKeys, 'FK to table3 should be added.');
1303
        self::assertEquals('table3', $actual->changedTables['table2']->addedForeignKeys[0]->getForeignTableName());
1304
    }
1305
}
1306