Passed
Pull Request — master (#431)
by Wilmer
02:38
created

SchemaTest   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 461
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 254
dl 0
loc 461
rs 10
c 2
b 1
f 0
wmc 26

20 Methods

Rating   Name   Duplication   Size   Complexity  
A testNormaliceRowKeyCase() 0 13 1
A testGetColumnPhpType() 0 33 1
A testGetSchemaPrimaryKeys() 0 15 1
A testRefreshTableSchema() 0 20 1
A testGetSchemaNames() 0 12 1
A testGetSchemaIndexes() 0 24 2
A testGetSchemaNamesWithSchema() 0 8 1
A testGetSchemaDefaultValues() 0 23 2
A createTableSchemaStub() 0 52 1
A testSetTableMetadata() 0 15 1
A testGetSchemaChecks() 0 23 2
A testGetSchemaForeignKeys() 0 24 2
A testFindTableNames() 0 10 1
A testGetTableSchemas() 0 16 2
A testGetSchemaUniques() 0 18 2
A testFindViewNames() 0 7 1
A testGetViewNames() 0 7 1
A getTableSchema() 0 18 1
A testRefreshTableSchemaWithSchemaCaseDisabled() 0 20 1
A testResolveTableName() 0 10 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Tests\Schema;
6
7
use ReflectionException;
8
use Yiisoft\Db\Constraint\CheckConstraint;
9
use Yiisoft\Db\Constraint\Constraint;
10
use Yiisoft\Db\Constraint\DefaultValueConstraint;
11
use Yiisoft\Db\Constraint\ForeignKeyConstraint;
12
use Yiisoft\Db\Constraint\IndexConstraint;
13
use Yiisoft\Db\Exception\NotSupportedException;
14
use Yiisoft\Db\Schema\ColumnSchema;
15
use Yiisoft\Db\Schema\TableSchemaInterface;
16
use Yiisoft\Db\Tests\AbstractSchemaTest;
17
use Yiisoft\Db\Tests\Support\Assert;
18
use Yiisoft\Db\Tests\Support\DbHelper;
19
use Yiisoft\Db\Tests\Support\Stub\Schema;
20
use Yiisoft\Db\Tests\Support\Stub\TableSchema;
21
use Yiisoft\Db\Tests\Support\TestTrait;
22
23
/**
24
 * @group db
25
 *
26
 * @psalm-suppress PropertyNotSetInConstructor
27
 */
28
final class SchemaTest extends AbstractSchemaTest
29
{
30
    use TestTrait;
31
32
    /**
33
     * @throws ReflectionException
34
     */
35
    public function testFindTableNames(): void
36
    {
37
        $db = $this->getConnection();
38
39
        $schema = $db->getSchema();
40
41
        $this->expectException(NotSupportedException::class);
42
        $this->expectExceptionMessage('Yiisoft\Db\Tests\Support\Stub\Schema does not support fetching all table names.');
43
44
        Assert::invokeMethod($schema, 'findTableNames', ['dbo']);
45
    }
46
47
    /**
48
     * @throws ReflectionException
49
     */
50
    public function testFindViewNames(): void
51
    {
52
        $db = $this->getConnection();
53
54
        $schema = $db->getSchema();
55
56
        $this->assertSame([], Assert::invokeMethod($schema, 'findViewNames', ['dbo']));
57
    }
58
59
    /**
60
     * @throws ReflectionException
61
     */
62
    public function testGetColumnPhpType(): void
63
    {
64
        $db = $this->getConnection();
65
66
        $schema = $db->getSchema();
67
68
        $columnBigInt = new ColumnSchema();
69
        $columnBigInt->type('bigint');
70
71
        $columnBoolean = new ColumnSchema();
72
        $columnBoolean->type('boolean');
73
74
        $columnInteger = new ColumnSchema();
75
        $columnInteger->type('integer');
76
77
        $columnString = new ColumnSchema();
78
        $columnString->type('string');
79
80
        $this->assertSame(
81
            'integer',
82
            Assert::invokeMethod($schema, 'getColumnPhpType', [$columnBigInt]),
83
        );
84
        $this->assertSame(
85
            'boolean',
86
            Assert::invokeMethod($schema, 'getColumnPhpType', [$columnBoolean]),
87
        );
88
        $this->assertSame(
89
            'integer',
90
            Assert::invokeMethod($schema, 'getColumnPhpType', [$columnInteger]),
91
        );
92
        $this->assertSame(
93
            'string',
94
            Assert::invokeMethod($schema, 'getColumnPhpType', [$columnString]),
95
        );
96
    }
97
98
    /**
99
     * @throws NotSupportedException
100
     */
101
    public function testGetSchemaChecks(): void
102
    {
103
        $db = $this->getConnection();
104
105
        $checkConstraint = [
106
            (new CheckConstraint())
107
                ->columnNames(['col1', 'col2'])
108
                ->expression('col1 > col2')
109
                ->name('check_1'),
110
        ];
111
        $schemaMock = $this->getMockBuilder(Schema::class)
112
            ->onlyMethods(['findTableNames', 'loadTableChecks'])
113
            ->setConstructorArgs([$db, DbHelper::getSchemaCache()])
114
            ->getMock();
115
        $schemaMock->expects($this->once())->method('findTableNames')->willReturn(['T_constraints_1']);
116
        $schemaMock->expects($this->once())->method('loadTableChecks')->willReturn($checkConstraint);
117
        $tableChecks = $schemaMock->getSchemaChecks();
118
119
        $this->assertIsArray($tableChecks);
120
121
        foreach ($tableChecks as $checks) {
122
            $this->assertIsArray($checks);
123
            $this->assertContainsOnlyInstancesOf(CheckConstraint::class, $checks);
124
        }
125
    }
126
127
    /**
128
     * @throws NotSupportedException
129
     */
130
    public function testGetSchemaDefaultValues(): void
131
    {
132
        $db = $this->getConnection();
133
134
        $defaultValuesConstraint = [
135
            (new DefaultValueConstraint())
136
                ->columnNames(['C_default'])
137
                ->name('DF__T_constra__C_def__6203C3C6')
138
                ->value('((0))'),
139
        ];
140
        $schemaMock = $this->getMockBuilder(Schema::class)
141
            ->onlyMethods(['findTableNames', 'loadTableDefaultValues'])
142
            ->setConstructorArgs([$db, DbHelper::getSchemaCache()])
143
            ->getMock();
144
        $schemaMock->expects($this->once())->method('findTableNames')->willReturn(['T_constraints_1']);
145
        $schemaMock->expects($this->once())->method('loadTableDefaultValues')->willReturn($defaultValuesConstraint);
146
        $tableDefaultValues = $schemaMock->getSchemaDefaultValues();
147
148
        $this->assertIsArray($tableDefaultValues);
149
150
        foreach ($tableDefaultValues as $defaultValues) {
151
            $this->assertIsArray($defaultValues);
152
            $this->assertContainsOnlyInstancesOf(DefaultValueConstraint::class, $defaultValues);
153
        }
154
    }
155
156
    /**
157
     * @throws NotSupportedException
158
     */
159
    public function testGetSchemaForeignKeys(): void
160
    {
161
        $db = $this->getConnection();
162
163
        $foreingKeysConstraint = [
164
            (new ForeignKeyConstraint())
165
                ->name('CN_constraints_3')
166
                ->columnNames(['C_fk_id_1, C_fk_id_2'])
167
                ->foreignTableName('T_constraints_2')
168
                ->foreignColumnNames(['C_id_1', 'C_id_2']),
169
        ];
170
        $schemaMock = $this->getMockBuilder(Schema::class)
171
            ->onlyMethods(['findTableNames', 'loadTableForeignKeys'])
172
            ->setConstructorArgs([$db, DbHelper::getSchemaCache()])
173
            ->getMock();
174
        $schemaMock->expects($this->once())->method('findTableNames')->willReturn(['T_constraints_1']);
175
        $schemaMock->expects($this->once())->method('loadTableForeignKeys')->willReturn($foreingKeysConstraint);
176
        $tableForeignKeys = $schemaMock->getSchemaForeignKeys();
177
178
        $this->assertIsArray($tableForeignKeys);
179
180
        foreach ($tableForeignKeys as $foreignKeys) {
181
            $this->assertIsArray($foreignKeys);
182
            $this->assertContainsOnlyInstancesOf(ForeignKeyConstraint::class, $foreignKeys);
183
        }
184
    }
185
186
    /**
187
     * @throws NotSupportedException
188
     */
189
    public function testGetSchemaIndexes(): void
190
    {
191
        $db = $this->getConnection();
192
193
        $indexConstraint = [
194
            (new IndexConstraint())
195
                ->name('PK__T_constr__A9FAE80AC2B18E65')
196
                ->columnNames(['"C_id'])
197
                ->unique(true)
198
                ->primary(true),
199
        ];
200
        $schemaMock = $this->getMockBuilder(Schema::class)
201
            ->onlyMethods(['findTableNames', 'loadTableIndexes'])
202
            ->setConstructorArgs([$db, DbHelper::getSchemaCache()])
203
            ->getMock();
204
        $schemaMock->expects($this->once())->method('findTableNames')->willReturn(['T_constraints_1']);
205
        $schemaMock->expects($this->once())->method('loadTableIndexes')->willReturn($indexConstraint);
206
        $tableIndexes = $schemaMock->getSchemaIndexes();
207
208
        $this->assertIsArray($tableIndexes);
209
210
        foreach ($tableIndexes as $indexes) {
211
            $this->assertIsArray($indexes);
212
            $this->assertContainsOnlyInstancesOf(IndexConstraint::class, $indexes);
213
        }
214
    }
215
216
    public function testGetSchemaNames(): void
217
    {
218
        $db = $this->getConnection();
219
220
        $schema = $db->getSchema();
221
222
        $this->expectException(NotSupportedException::class);
223
        $this->expectExceptionMessage(
224
            'Yiisoft\Db\Tests\Support\Stub\Schema does not support fetching all schema names.'
225
        );
226
227
        $schema->getSchemaNames();
228
    }
229
230
    /**
231
     * @throws NotSupportedException
232
     * @throws ReflectionException
233
     */
234
    public function testGetSchemaNamesWithSchema(): void
235
    {
236
        $db = $this->getConnection();
237
238
        $schema = $db->getSchema();
239
        Assert::setInaccessibleProperty($schema, 'schemaNames', ['dbo', 'public']);
240
241
        $this->assertSame(['dbo', 'public'], $schema->getSchemaNames());
242
    }
243
244
    /**
245
     * @throws NotSupportedException
246
     */
247
    public function testGetSchemaPrimaryKeys(): void
248
    {
249
        $db = $this->getConnection();
250
251
        $pksConstraint = (new Constraint())->name('PK__T_constr__A9FAE80AC2B18E65')->columnNames(['"C_id']);
252
        $schemaMock = $this->getMockBuilder(Schema::class)
253
            ->onlyMethods(['findTableNames', 'loadTablePrimaryKey'])
254
            ->setConstructorArgs([$db, DbHelper::getSchemaCache()])
255
            ->getMock();
256
        $schemaMock->expects($this->once())->method('findTableNames')->willReturn(['T_constraints_1']);
257
        $schemaMock->expects($this->once())->method('loadTablePrimaryKey')->willReturn($pksConstraint);
258
        $tablePks = $schemaMock->getSchemaPrimaryKeys();
259
260
        $this->assertIsArray($tablePks);
261
        $this->assertContainsOnlyInstancesOf(Constraint::class, $tablePks);
262
    }
263
264
    /**
265
     * @throws NotSupportedException
266
     */
267
    public function testGetSchemaUniques(): void
268
    {
269
        $db = $this->getConnection();
270
271
        $uniquesConstraint = [(new Constraint())->name('CN_unique')->columnNames(['C_unique'])];
272
        $schemaMock = $this->getMockBuilder(Schema::class)
273
            ->onlyMethods(['findTableNames', 'loadTableUniques'])
274
            ->setConstructorArgs([$db, DbHelper::getSchemaCache()])
275
            ->getMock();
276
        $schemaMock->expects($this->once())->method('findTableNames')->willReturn(['T_constraints_1']);
277
        $schemaMock->expects($this->once())->method('loadTableUniques')->willReturn($uniquesConstraint);
278
        $tableUniques = $schemaMock->getSchemaUniques();
279
280
        $this->assertIsArray($tableUniques);
281
282
        foreach ($tableUniques as $uniques) {
283
            $this->assertIsArray($uniques);
284
            $this->assertContainsOnlyInstancesOf(Constraint::class, $uniques);
285
        }
286
    }
287
288
    public function getTableSchema(): void
289
    {
290
        $db = $this->getConnection();
291
292
        $schemaMock = $this->getMockBuilder(Schema::class)
293
            ->onlyMethods(['findTableNames', 'loadTableSchema'])
294
            ->setConstructorArgs([$db, DbHelper::getSchemaCache()])
295
            ->getMock();
296
        $schemaMock->expects($this->once())->method('findTableNames')->willReturn(['T_constraints_1']);
297
        $schemaMock->expects($this->once())->method('loadTableSchema')->willReturn($this->createTableSchemaStub());
298
        $table = $schemaMock->getTableSchema('T_constraints_1');
299
300
        $this->assertInstanceOf(TableSchema::class, $table);
301
        $this->assertSame('T_constraints_1', $table->getName());
302
        $this->assertSame('dbo', $table->getSchemaName());
303
        $this->assertSame('T_constraints_1', $table->getFullName());
304
        $this->assertSame(['C_id'], $table->getPrimaryKey());
305
        $this->assertSame(['C_id', 'C_not_null', 'C_check', 'C_default', 'C_unique'], $table->getColumnNames());
306
    }
307
308
    /**
309
     * @throws NotSupportedException
310
     */
311
    public function testGetTableSchemas(): void
312
    {
313
        $db = $this->getConnection();
314
315
        $schemaMock = $this->getMockBuilder(Schema::class)
316
            ->onlyMethods(['findTableNames', 'loadTableSchema'])
317
            ->setConstructorArgs([$db, DbHelper::getSchemaCache()])
318
            ->getMock();
319
        $schemaMock->expects($this->once())->method('findTableNames')->willReturn(['T_constraints_1']);
320
        $schemaMock->expects($this->once())->method('loadTableSchema')->willReturn($this->createTableSchemaStub());
321
        $tables = $schemaMock->getTableSchemas('dbo');
322
323
        $this->assertCount(count($schemaMock->getTableNames('dbo')), $tables);
324
325
        foreach ($tables as $table) {
326
            $this->assertInstanceOf(TableSchemaInterface::class, $table);
327
        }
328
    }
329
330
    public function testGetViewNames(): void
331
    {
332
        $db = $this->getConnection();
333
334
        $schema = $db->getSchema();
335
336
        $this->assertSame([], $schema->getViewNames());
337
    }
338
339
    /**
340
     * @throws ReflectionException
341
     */
342
    public function testNormaliceRowKeyCase(): void
343
    {
344
        $db = $this->getConnection();
345
346
        $schema = $db->getSchema();
347
348
        $this->assertSame(
349
            ['fk_test' => 1],
350
            Assert::InvokeMethod($schema, 'normalizeRowKeyCase', [['Fk_test' => 1], false]),
351
        );
352
        $this->assertSame(
353
            ['FK_test' => ['uk_test' => 1]],
354
            Assert::InvokeMethod($schema, 'normalizeRowKeyCase', [['FK_test' => ['UK_test' => 1]], true]),
355
        );
356
    }
357
358
    public function testRefreshTableSchema(): void
359
    {
360
        $db = $this->getConnection(true);
361
362
        $schemaMock = $this->getMockBuilder(Schema::class)
363
            ->onlyMethods(['findTableNames', 'loadTableSchema'])
364
            ->setConstructorArgs([$db, DbHelper::getSchemaCache()])
365
            ->getMock();
366
        $schemaMock
367
            ->expects($this->exactly(2))
368
            ->method('loadTableSchema')
369
            ->will(
370
                $this->onConsecutiveCalls($this->createTableSchemaStub(), $this->createTableSchemaStub())
371
            );
372
        $schemaMock->schemaCacheEnable(true);
373
        $noCacheTable = $schemaMock->getTableSchema('T_constraints_1', true);
374
        $schemaMock->refreshTableSchema('T_constraints_1');
375
        $refreshedTable = $schemaMock->getTableSchema('T_constraints_1');
376
377
        $this->assertNotSame($noCacheTable, $refreshedTable);
378
    }
379
380
    public function testRefreshTableSchemaWithSchemaCaseDisabled(): void
381
    {
382
        $db = $this->getConnection(true);
383
384
        $schemaMock = $this->getMockBuilder(Schema::class)
385
            ->onlyMethods(['findTableNames', 'loadTableSchema'])
386
            ->setConstructorArgs([$db, DbHelper::getSchemaCache()])
387
            ->getMock();
388
        $schemaMock
389
            ->expects($this->exactly(2))
390
            ->method('loadTableSchema')
391
            ->will(
392
                $this->onConsecutiveCalls($this->createTableSchemaStub(), $this->createTableSchemaStub())
393
            );
394
        $schemaMock->schemaCacheEnable(false);
395
        $noCacheTable = $schemaMock->getTableSchema('T_constraints_1', true);
396
        $schemaMock->refreshTableSchema('T_constraints_1');
397
        $refreshedTable = $schemaMock->getTableSchema('T_constraints_1');
398
399
        $this->assertNotSame($noCacheTable, $refreshedTable);
400
    }
401
402
    /**
403
     * @throws ReflectionException
404
     */
405
    public function testResolveTableName(): void
406
    {
407
        $db = $this->getConnection();
408
409
        $schema = $db->getSchema();
410
411
        $this->expectException(NotSupportedException::class);
412
        $this->expectExceptionMessage('Yiisoft\Db\Tests\Support\Stub\Schema does not support resolving table names.');
413
414
        Assert::invokeMethod($schema, 'resolveTableName', ['customer']);
415
    }
416
417
    /**
418
     * @throws ReflectionException
419
     */
420
    public function testSetTableMetadata(): void
421
    {
422
        $db = $this->getConnection();
423
424
        $schema = $db->getSchema();
425
426
        $checkConstraint = [
427
            (new CheckConstraint())
428
                ->columnNames(['col1', 'col2'])
429
                ->expression('col1 > col2')
430
                ->name('check_1'),
431
        ];
432
        Assert::invokeMethod($schema, 'setTableMetadata', ['T_constraints_1', 'checks', $checkConstraint]);
433
434
        $this->assertSame($checkConstraint, $schema->getTableChecks('T_constraints_1'));
435
    }
436
437
    private function createTableSchemaStub(): TableSchemaInterface
438
    {
439
        // defined column C_id
440
        $columnCid = new ColumnSchema();
441
        $columnCid->autoIncrement(true);
442
        $columnCid->dbType('int');
443
        $columnCid->primaryKey(true);
444
        $columnCid->name('C_id');
445
        $columnCid->phpType('integer');
446
        $columnCid->type('integer');
447
448
        // defined column C_not_null
449
        $columnCNotNull = new ColumnSchema();
450
        $columnCNotNull->dbType('int');
451
        $columnCNotNull->name('C_not_null');
452
        $columnCNotNull->phpType('int');
453
        $columnCNotNull->type('int');
454
455
        // defined column C_check
456
        $columnCCheck = new ColumnSchema();
457
        $columnCCheck->dbType('varchar(255)');
458
        $columnCCheck->name('C_check');
459
        $columnCCheck->phpType('string');
460
        $columnCCheck->type('string');
461
462
        // defined column C_default
463
        $columnCDefault = new ColumnSchema();
464
        $columnCDefault->dbType('int');
465
        $columnCDefault->name('C_default');
466
        $columnCDefault->phpType('integer');
467
        $columnCDefault->type('integer');
468
469
        // defined column C_unique
470
        $columnCUnique = new ColumnSchema();
471
        $columnCUnique->dbType('int');
472
        $columnCUnique->name('C_unique');
473
        $columnCUnique->phpType('integer');
474
        $columnCUnique->type('integer');
475
476
        // defined table T_constraints_1
477
        $tableSchema = new TableSchema();
478
        $tableSchema->columns('C_id', $columnCid);
479
        $tableSchema->columns('C_not_null', $columnCNotNull);
480
        $tableSchema->columns('C_check', $columnCCheck);
481
        $tableSchema->columns('C_default', $columnCDefault);
482
        $tableSchema->columns('C_unique', $columnCUnique);
483
        $tableSchema->fullName('T_constraints_1');
484
        $tableSchema->name('T_constraints_1');
485
        $tableSchema->primaryKey('C_id');
486
        $tableSchema->schemaName('dbo');
487
488
        return $tableSchema;
489
    }
490
}
491