Merge pull request #19552 from kamil-tekiela/Fix-default-values
[phpmyadmin.git] / tests / unit / NormalizationTest.php
blob6c53aa3573fa36d4b6a0a49fd44864ad1f2205e4
1 <?php
3 declare(strict_types=1);
5 namespace PhpMyAdmin\Tests;
7 use PhpMyAdmin\Column;
8 use PhpMyAdmin\Config;
9 use PhpMyAdmin\ConfigStorage\Relation;
10 use PhpMyAdmin\Current;
11 use PhpMyAdmin\Dbal\ConnectionType;
12 use PhpMyAdmin\Dbal\DatabaseInterface;
13 use PhpMyAdmin\Message;
14 use PhpMyAdmin\Normalization;
15 use PhpMyAdmin\Template;
16 use PhpMyAdmin\Tests\Stubs\DbiDummy;
17 use PhpMyAdmin\Tests\Stubs\DummyResult;
18 use PhpMyAdmin\Transformations;
19 use PhpMyAdmin\Types;
20 use PhpMyAdmin\UserPrivileges;
21 use PHPUnit\Framework\Attributes\CoversClass;
22 use stdClass;
24 use function __;
25 use function _pgettext;
26 use function json_encode;
28 #[CoversClass(Normalization::class)]
29 class NormalizationTest extends AbstractTestCase
31 protected DatabaseInterface $dbi;
33 protected DbiDummy $dummyDbi;
35 private Normalization $normalization;
37 /**
38 * prepares environment for tests
40 protected function setUp(): void
42 parent::setUp();
44 $this->dummyDbi = $this->createDbiDummy();
45 $this->dbi = $this->createDatabaseInterface($this->dummyDbi);
46 DatabaseInterface::$instance = $this->dbi;
47 $config = Config::getInstance();
48 $config->settings['LimitChars'] = 50;
49 $config->settings['ServerDefault'] = 'PMA_server';
50 $config->settings['ShowHint'] = true;
51 $config->settings['CharEditing'] = '';
52 $config->settings['ActionLinksMode'] = 'icons';
53 Current::$database = 'PMA_db';
54 Current::$table = 'PMA_table';
55 $config->selectedServer['DisableIS'] = false;
56 $_POST['change_column'] = null;
58 //$_SESSION
60 //mock DBI
61 $dbi = $this->getMockBuilder(DatabaseInterface::class)
62 ->disableOriginalConstructor()
63 ->getMock();
64 $dbi->types = new Types($dbi);
65 DatabaseInterface::$instance = $dbi;
66 // set expectations
67 $dbi->expects(self::any())
68 ->method('selectDb')
69 ->willReturn(true);
70 $dbi->expects(self::any())
71 ->method('getColumns')
72 ->willReturn([
73 'id' => new Column('id', 'integer', null, false, '', null, '', '', ''),
74 'col1' => new Column('col1', 'varchar(100)', null, false, '', null, '', '', ''),
75 'col2' => new Column('col2', 'DATETIME', null, false, '', null, '', '', ''),
76 ]);
77 $dbi->expects(self::any())
78 ->method('getColumnNames')
79 ->willReturn(['id', 'col1', 'col2']);
80 $map = [
81 ['PMA_db', 'PMA_table1', ConnectionType::User, []],
82 ['PMA_db', 'PMA_table', ConnectionType::User, [['Key_name' => 'PRIMARY', 'Column_name' => 'id']]],
84 'PMA_db',
85 'PMA_table2',
86 ConnectionType::User,
87 [['Key_name' => 'PRIMARY','Column_name' => 'id'], ['Key_name' => 'PRIMARY','Column_name' => 'col1']],
90 $dbi->expects(self::any())
91 ->method('getTableIndexes')
92 ->willReturnMap($map);
93 $dbi->expects(self::any())
94 ->method('tryQuery')
95 ->willReturn(self::createStub(DummyResult::class));
96 $dbi->expects(self::any())
97 ->method('fetchSingleRow')
98 ->willReturn(['`id`_cnt' => 0, '`col1`_cnt' => 0, '`col2`_cnt' => 0]);
100 $this->normalization = new Normalization($dbi, new Relation($dbi), new Transformations(), new Template());
104 * Test for getHtmlForColumnsList
106 public function testGetHtmlForColumnsList(): void
108 $db = 'PMA_db';
109 $table = 'PMA_table';
110 self::assertStringContainsString(
111 '<option value="id">id [ integer ]</option>',
112 $this->normalization->getHtmlForColumnsList($table, $db),
114 self::assertSame(
115 '<input type="checkbox" value="col1">col1 [ varchar(100) ]<br>',
116 $this->normalization->getHtmlForColumnsList($table, $db, 'String', 'checkbox'),
121 * Test for getHtmlForCreateNewColumn
123 public function testGetHtmlForCreateNewColumn(): void
125 $config = Config::getInstance();
126 $config->settings['BrowseMIME'] = true;
127 $config->settings['MaxRows'] = 25;
128 $userPrivileges = new UserPrivileges();
129 $config->selectedServer['DisableIS'] = false;
130 DatabaseInterface::$instance = $this->dbi;
131 $db = 'testdb';
132 $table = 'mytable';
133 $numFields = 1;
134 $normalization = new Normalization(
135 $this->dbi,
136 new Relation($this->dbi),
137 new Transformations(),
138 new Template(),
140 $result = $normalization->getHtmlForCreateNewColumn($userPrivileges, $numFields, $db, $table);
141 self::assertStringContainsString('<table id="table_columns"', $result);
145 * Test for getHtmlFor1NFStep1
147 public function testGetHtmlFor1NFStep1(): void
149 $db = 'PMA_db';
150 $table = 'PMA_table';
151 $normalizedTo = '1nf';
152 $result = $this->normalization->getHtmlFor1NFStep1($db, $table, $normalizedTo);
153 self::assertStringContainsString('<h3>' . __('First step of normalization (1NF)') . '</h3>', $result);
154 self::assertStringContainsString('<div class="card" id="mainContent"', $result);
155 self::assertStringContainsString('<div class="card-header">' . __('Step 1.'), $result);
157 self::assertStringContainsString('<h4', $result);
159 self::assertStringContainsString('<p', $result);
161 self::assertStringContainsString("<select id='selectNonAtomicCol'", $result);
163 self::assertStringContainsString(
164 $this->normalization->getHtmlForColumnsList(
165 $db,
166 $table,
167 _pgettext('string types', 'String'),
169 $result,
174 * Test for getHtmlContentsFor1NFStep2
176 public function testGetHtmlContentsFor1NFStep2(): void
178 $db = 'PMA_db';
179 $table = 'PMA_table1';
180 $result = $this->normalization->getHtmlContentsFor1NFStep2($db, $table);
181 self::assertArrayHasKey('legendText', $result);
182 self::assertArrayHasKey('headText', $result);
183 self::assertArrayHasKey('subText', $result);
184 self::assertArrayHasKey('hasPrimaryKey', $result);
185 self::assertArrayHasKey('extra', $result);
186 self::assertStringContainsString('<a href="#" id="createPrimaryKey">', $result['subText']);
187 self::assertStringContainsString('<a href="#" id="addNewPrimary">', $result['extra']);
188 self::assertSame('0', $result['hasPrimaryKey']);
189 self::assertStringContainsString(__('Step 1.') . 2, $result['legendText']);
190 $result1 = $this->normalization->getHtmlContentsFor1NFStep2($db, 'PMA_table');
191 self::assertSame('1', $result1['hasPrimaryKey']);
195 * Test for getHtmlContentsFor1NFStep4
197 public function testGetHtmlContentsFor1NFStep4(): void
199 $db = 'PMA_db';
200 $table = 'PMA_table';
201 $result = $this->normalization->getHtmlContentsFor1NFStep4($db, $table);
202 self::assertArrayHasKey('legendText', $result);
203 self::assertArrayHasKey('headText', $result);
204 self::assertArrayHasKey('subText', $result);
205 self::assertArrayHasKey('extra', $result);
206 self::assertStringContainsString(__('Step 1.') . 4, $result['legendText']);
207 self::assertStringContainsString(
208 $this->normalization->getHtmlForColumnsList($db, $table, 'all', 'checkbox'),
209 $result['extra'],
211 self::assertStringContainsString(
212 '<input class="btn btn-secondary" type="submit" id="removeRedundant"',
213 $result['extra'],
218 * Test for getHtmlContentsFor1NFStep3
220 public function testGetHtmlContentsFor1NFStep3(): void
222 $db = 'PMA_db';
223 $table = 'PMA_table';
224 $result = $this->normalization->getHtmlContentsFor1NFStep3($db, $table);
225 self::assertArrayHasKey('legendText', $result);
226 self::assertArrayHasKey('headText', $result);
227 self::assertArrayHasKey('subText', $result);
228 self::assertArrayHasKey('extra', $result);
229 self::assertArrayHasKey('primary_key', $result);
230 self::assertStringContainsString(__('Step 1.') . 3, $result['legendText']);
231 self::assertStringContainsString(
232 $this->normalization->getHtmlForColumnsList($db, $table, 'all', 'checkbox'),
233 $result['extra'],
235 self::assertStringContainsString(
236 '<input class="btn btn-secondary" type="submit" id="moveRepeatingGroup"',
237 $result['extra'],
239 self::assertSame(json_encode(['id']), $result['primary_key']);
243 * Test for getHtmlFor2NFstep1
245 public function testGetHtmlFor2NFstep1(): void
247 $db = 'PMA_db';
248 $table = 'PMA_table';
249 $result = $this->normalization->getHtmlFor2NFstep1($db, $table);
250 self::assertArrayHasKey('legendText', $result);
251 self::assertArrayHasKey('headText', $result);
252 self::assertArrayHasKey('subText', $result);
253 self::assertArrayHasKey('extra', $result);
254 self::assertArrayHasKey('primary_key', $result);
255 self::assertStringContainsString(__('Step 2.') . 1, $result['legendText']);
256 self::assertSame('id', $result['primary_key']);
257 $result1 = $this->normalization->getHtmlFor2NFstep1($db, 'PMA_table2');
258 self::assertSame('id, col1', $result1['primary_key']);
259 self::assertStringContainsString('<a href="#" id="showPossiblePd"', $result1['headText']);
260 self::assertStringContainsString('<input type="checkbox" name="pd" value="id"', $result1['extra']);
264 * Test for getHtmlForNewTables2NF
266 public function testGetHtmlForNewTables2NF(): void
268 $table = 'PMA_table';
269 $partialDependencies = ['col1' => ['col2']];
270 $result = $this->normalization->getHtmlForNewTables2NF($partialDependencies, $table);
271 self::assertStringContainsString('<input type="text" name="col1"', $result);
275 * Test for createNewTablesFor2NF
277 public function testCreateNewTablesFor2NF(): void
279 $table = 'PMA_table';
280 $db = 'PMA_db';
281 $tablesName = new stdClass();
282 $tablesName->id = 'PMA_table';
283 $tablesName->col1 = 'PMA_table1';
284 $partialDependencies = ['id' => ['col2']];
285 $result = $this->normalization->createNewTablesFor2NF($partialDependencies, $tablesName, $table, $db);
286 self::assertArrayHasKey('legendText', $result);
287 self::assertArrayHasKey('headText', $result);
288 self::assertArrayHasKey('queryError', $result);
289 $partialDependencies = ['id' => ['col2'], 'col1' => ['col2']];
290 $result1 = $this->normalization->createNewTablesFor2NF($partialDependencies, $tablesName, $table, $db);
291 self::assertArrayHasKey('extra', $result1);
292 self::assertSame(__('End of step'), $result1['legendText']);
293 self::assertSame('', $result1['extra']);
297 * Test for getHtmlForNewTables3NF
299 public function testGetHtmlForNewTables3NF(): void
301 $tables = ['PMA_table' => ['col1']];
302 $db = 'PMA_db';
303 $dependencies = new stdClass();
304 $dependencies->col1 = ['col2'];
305 $result = $this->normalization->getHtmlForNewTables3NF($dependencies, $tables, $db);
306 self::assertEquals(
307 ['html' => '', 'success' => true, 'newTables' => []],
308 $result,
310 $tables = ['PMA_table' => ['col1', 'PMA_table']];
311 // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
312 $dependencies->PMA_table = ['col4', 'col5'];
313 $result1 = $this->normalization->getHtmlForNewTables3NF($dependencies, $tables, $db);
314 self::assertStringContainsString('<input type="text" name="PMA_table"', $result1['html']);
315 self::assertSame(
317 'PMA_table' => [
318 'PMA_table' => ['pk' => 'col1', 'nonpk' => 'col2'],
319 'table2' => ['pk' => 'id', 'nonpk' => 'col4, col5'],
322 $result1['newTables'],
327 * Test for createNewTablesFor3NF
329 public function testCreateNewTablesFor3NF(): void
331 $db = 'PMA_db';
332 $newTables = [
333 'PMA_table' => [
334 'PMA_table' => ['pk' => 'id', 'nonpk' => 'col1, col2'],
335 'table1' => ['pk' => 'col2', 'nonpk' => 'col3, col4'],
338 $result = $this->normalization->createNewTablesFor3NF($newTables, $db);
339 self::assertArrayHasKey('legendText', $result);
340 self::assertArrayHasKey('headText', $result);
341 self::assertArrayHasKey('queryError', $result);
342 $newTables1 = [];
343 $result1 = $this->normalization->createNewTablesFor3NF($newTables1, $db);
344 self::assertArrayHasKey('queryError', $result1);
345 self::assertSame(__('End of step'), $result1['legendText']);
346 self::assertFalse($result1['queryError']);
350 * Test for moveRepeatingGroup
352 public function testMoveRepeatingGroup(): void
354 $repeatingColumns = 'col1, col2';
355 $primaryColumns = 'id,col1';
356 $newTable = 'PMA_newTable';
357 $newColumn = 'PMA_newCol';
358 $table = 'PMA_table';
359 $db = 'PMA_db';
360 $result = $this->normalization->moveRepeatingGroup(
361 $repeatingColumns,
362 $primaryColumns,
363 $newTable,
364 $newColumn,
365 $table,
366 $db,
368 self::assertArrayHasKey('queryError', $result);
369 self::assertArrayHasKey('message', $result);
370 self::assertInstanceOf(Message::class, $result['message']);
374 * Test for getHtmlFor3NFstep1
376 public function testGetHtmlFor3NFstep1(): void
378 $db = 'PMA_db';
379 $tables = ['PMA_table'];
380 $result = $this->normalization->getHtmlFor3NFstep1($db, $tables);
381 self::assertArrayHasKey('legendText', $result);
382 self::assertArrayHasKey('headText', $result);
383 self::assertArrayHasKey('subText', $result);
384 self::assertArrayHasKey('extra', $result);
385 self::assertStringContainsString(__('Step 3.') . 1, $result['legendText']);
386 self::assertStringContainsString('<form', $result['extra']);
387 self::assertStringContainsString('<input type="checkbox" name="pd" value="col1"', $result['extra']);
388 $result1 = $this->normalization->getHtmlFor3NFstep1($db, ['PMA_table2']);
389 self::assertSame('', $result1['subText']);
393 * Test for findPartialDependencies
395 public function testFindPartialDependencies(): void
397 $table = 'PMA_table2';
398 $db = 'PMA_db';
399 $result = $this->normalization->findPartialDependencies($table, $db);
400 self::assertStringContainsString('<div class="dependencies_box"', $result);
401 self::assertStringContainsString(__('No partial dependencies found!'), $result);
405 * Test for getAllCombinationPartialKeys
407 public function testGetAllCombinationPartialKeys(): void
409 $primaryKey = ['id', 'col1', 'col2'];
410 $result = $this->callFunction(
411 $this->normalization,
412 Normalization::class,
413 'getAllCombinationPartialKeys',
414 [$primaryKey],
417 self::assertSame(
418 ['', 'id', 'col1', 'col1,id', 'col2', 'col2,id', 'col2,col1'],
419 $result,