diff --git a/libraries/classes/TablePartitionDefinition.php b/libraries/classes/TablePartitionDefinition.php index be9e8c8058..b639aacc43 100644 --- a/libraries/classes/TablePartitionDefinition.php +++ b/libraries/classes/TablePartitionDefinition.php @@ -9,7 +9,7 @@ use function array_merge; use function array_splice; use function min; -class TablePartitionDefinition +final class TablePartitionDefinition { /** * @param array|null $details Details that may be pre-filled @@ -28,7 +28,7 @@ class TablePartitionDefinition /** * @return array */ - protected static function generateDetails(): array + private static function generateDetails(): array { $partitionDetails = self::extractDetailsFromRequest(); @@ -55,7 +55,7 @@ class TablePartitionDefinition * * @return array */ - protected static function extractDetailsFromRequest(): array + private static function extractDetailsFromRequest(): array { $partitionParams = [ 'partition_by' => null, @@ -79,10 +79,11 @@ class TablePartitionDefinition /** * @param string $paramLabel Label searched in request */ - protected static function extractPartitionCount(string $paramLabel): int + private static function extractPartitionCount(string $paramLabel): int { if (Core::isValid($_POST[$paramLabel], 'numeric')) { // MySQL's limit is 8192, so do not allow more + // @see https://dev.mysql.com/doc/refman/en/partitioning-limitations.html $count = min((int) $_POST[$paramLabel], 8192); } else { $count = 0; @@ -96,7 +97,7 @@ class TablePartitionDefinition * * @return array */ - protected static function extractPartitions(array $partitionDetails): array + private static function extractPartitions(array $partitionDetails): array { $partitionCount = $partitionDetails['partition_count']; $subpartitionCount = $partitionDetails['subpartition_count']; @@ -151,7 +152,7 @@ class TablePartitionDefinition } // No subpartitions - if ($subpartitionCount <= 1 || $partitionDetails['can_have_subpartitions'] !== true) { + if ($subpartitionCount < 2 || $partitionDetails['can_have_subpartitions'] !== true) { unset($partition['subpartitions'], $partition['subpartition_count']); continue; } diff --git a/test/classes/TablePartitionDefinitionTest.php b/test/classes/TablePartitionDefinitionTest.php new file mode 100644 index 0000000000..c04226de27 --- /dev/null +++ b/test/classes/TablePartitionDefinitionTest.php @@ -0,0 +1,265 @@ + $partitionBy, + 'partition_expr' => 'partition_expr', + 'subpartition_by' => 'subpartition_by', + 'subpartition_expr' => 'subpartition_expr', + 'partition_count' => $partitionCount > 0 ? $partitionCount : '', + 'subpartition_count' => $subPartitionCount > 0 ? $subPartitionCount : '', + 'can_have_subpartitions' => $canHaveSubpartitions, + 'value_enabled' => $valueEnabled, + 'partitions' => [ + [ + 'name' => 'part0', + 'value_type' => '', + 'value' => '', + 'engine' => '', + 'comment' => '', + 'data_directory' => '', + 'index_directory' => '', + 'max_rows' => '', + 'min_rows' => '', + 'tablespace' => '', + 'node_group' => '', + 'prefix' => 'partitions[0]', + 'subpartition_count' => 2, + 'subpartitions' => [ + [ + 'name' => 'part0_s0', + 'engine' => '', + 'comment' => '', + 'data_directory' => '', + 'index_directory' => '', + 'max_rows' => '', + 'min_rows' => '', + 'tablespace' => '', + 'node_group' => '', + 'prefix' => 'partitions[0][subpartitions][0]', + ], + [ + 'name' => 'part0_s1', + 'engine' => '', + 'comment' => '', + 'data_directory' => '', + 'index_directory' => '', + 'max_rows' => '', + 'min_rows' => '', + 'tablespace' => '', + 'node_group' => '', + 'prefix' => 'partitions[0][subpartitions][1]', + ], + ], + ], + [ + 'name' => 'p1', + 'value_type' => '', + 'value' => '', + 'engine' => '', + 'comment' => '', + 'data_directory' => '', + 'index_directory' => '', + 'max_rows' => '', + 'min_rows' => '', + 'tablespace' => '', + 'node_group' => '', + 'prefix' => 'partitions[1]', + 'subpartition_count' => 2, + 'subpartitions' => [ + [ + 'name' => 'p1_s0', + 'engine' => '', + 'comment' => '', + 'data_directory' => '', + 'index_directory' => '', + 'max_rows' => '', + 'min_rows' => '', + 'tablespace' => '', + 'node_group' => '', + 'prefix' => 'partitions[1][subpartitions][0]', + ], + [ + 'name' => 'p1_s1', + 'engine' => '', + 'comment' => '', + 'data_directory' => '', + 'index_directory' => '', + 'max_rows' => '', + 'min_rows' => '', + 'tablespace' => '', + 'node_group' => '', + 'prefix' => 'partitions[1][subpartitions][1]', + ], + ], + ], + ], + ]; + + if (! $canHaveSubpartitions && $partitionCount === 2) { + unset($expected['partitions'][0]['subpartition_count']); + unset($expected['partitions'][0]['subpartitions']); + unset($expected['partitions'][1]['subpartition_count']); + unset($expected['partitions'][1]['subpartitions']); + } + + if ($partitionCount < 2) { + unset($expected['partitions']); + } + + $_POST['partition_by'] = $partitionBy; + $_POST['partition_expr'] = 'partition_expr'; + $_POST['subpartition_by'] = 'subpartition_by'; + $_POST['subpartition_expr'] = 'subpartition_expr'; + $_POST['partition_count'] = (string) $partitionCount; + $_POST['subpartition_count'] = (string) $subPartitionCount; + $_POST['partitions'] = $partitions; + $_POST['ignored_key'] = 'ignored_value'; + + $actual = TablePartitionDefinition::getDetails(); + $this->assertEquals($expected, $actual); + } + + /** + * @psalm-return array[]>[]|null + * }> + */ + public function providerGetDetails(): array + { + return [ + 'partition by RANGE' => ['RANGE', true, true, 2, 2, [['name' => 'part0']]], + 'partition by RANGE COLUMNS' => ['RANGE COLUMNS', true, true, 2, 2, [['name' => 'part0']]], + 'partition by LIST' => ['LIST', true, true, 2, 2, [['name' => 'part0']]], + 'partition by LIST COLUMNS' => ['LIST COLUMNS', true, true, 2, 2, [['name' => 'part0']]], + 'partition by HASH' => ['HASH', false, false, 2, 2, [['name' => 'part0']]], + 'partition count === 0' => ['RANGE', false, true, 0, 0, null], + 'partition count === 1' => ['RANGE', false, true, 1, 1, null], + 'more partitions than the partition count' => [ + 'RANGE', + true, + true, + 2, + 2, + [['name' => 'part0'], ['name' => 'p1'], ['name' => 'p2']], + ], + 'more subpartitions than the subpartition count' => [ + 'RANGE', + true, + true, + 2, + 2, + [ + [ + 'name' => 'part0', + 'subpartitions' => [ + [ + 'name' => 'part0_s0', + 'engine' => '', + 'comment' => '', + 'data_directory' => '', + 'index_directory' => '', + 'max_rows' => '', + 'min_rows' => '', + 'tablespace' => '', + 'node_group' => '', + 'prefix' => 'partitions[1][subpartitions][0]', + ], + [ + 'name' => 'part0_s1', + 'engine' => '', + 'comment' => '', + 'data_directory' => '', + 'index_directory' => '', + 'max_rows' => '', + 'min_rows' => '', + 'tablespace' => '', + 'node_group' => '', + 'prefix' => 'partitions[1][subpartitions][1]', + ], + [ + 'name' => 'part0_s1', + 'engine' => '', + 'comment' => '', + 'data_directory' => '', + 'index_directory' => '', + 'max_rows' => '', + 'min_rows' => '', + 'tablespace' => '', + 'node_group' => '', + 'prefix' => 'partitions[1][subpartitions][1]', + ], + ], + ], + ], + ], + ]; + } + + public function testGetDetailsWithoutPostValues(): void + { + $_POST = []; + $expected = [ + 'partition_by' => null, + 'partition_expr' => null, + 'subpartition_by' => null, + 'subpartition_expr' => null, + 'partition_count' => '', + 'subpartition_count' => '', + 'can_have_subpartitions' => false, + 'value_enabled' => false, + ]; + + $actual = TablePartitionDefinition::getDetails($expected); + $this->assertEquals($expected, $actual); + + $actual = TablePartitionDefinition::getDetails(); + $this->assertEquals($expected, $actual); + } + + /** + * @dataProvider providerGetDetailsWithMaxPartitions + */ + public function testGetDetailsWithMaxPartitions(int $partitionCount, string $partitionCountFromPost): void + { + $_POST = ['partition_count' => $partitionCountFromPost]; + $actual = TablePartitionDefinition::getDetails(); + $this->assertArrayHasKey('partition_count', $actual); + $this->assertArrayHasKey('partitions', $actual); + $this->assertSame($partitionCount, $actual['partition_count']); + $this->assertIsArray($actual['partitions']); + $this->assertEquals($partitionCount, count($actual['partitions'])); + } + + /** + * @psalm-return array{0: int, 1: string}[] + */ + public function providerGetDetailsWithMaxPartitions(): array + { + return ['count within the limit' => [8192, '8192'], 'count above the limit' => [8192, '8193']]; + } +} diff --git a/test/classes/UserPasswordTest.php b/test/classes/UserPasswordTest.php new file mode 100644 index 0000000000..c799104f4f --- /dev/null +++ b/test/classes/UserPasswordTest.php @@ -0,0 +1,77 @@ +object = new UserPassword($serverPrivileges); + } + + /** + * @dataProvider providerSetChangePasswordMsg + */ + public function testSetChangePasswordMsg( + bool $error, + Message $message, + string $noPassword, + string $password, + string $passwordConfirmation + ): void { + $_POST['nopass'] = $noPassword; + $_POST['pma_pw'] = $password; + $_POST['pma_pw2'] = $passwordConfirmation; + $this->assertEquals(['error' => $error, 'msg' => $message], $this->object->setChangePasswordMsg()); + } + + /** + * @psalm-return array{0: bool, 1: Message, 2: string, 3: string, 4: string}[] + */ + public function providerSetChangePasswordMsg(): array + { + return [ + [false, Message::success('The profile has been updated.'), '1', '', ''], + [true, Message::error('The password is empty!'), '0', '', ''], + [true, Message::error('The password is empty!'), '0', 'a', ''], + [true, Message::error('The password is empty!'), '0', '', 'a'], + [true, Message::error('The passwords aren\'t the same!'), '0', 'a', 'b'], + [true, Message::error('Password is too long!'), '0', str_repeat('a', 257), str_repeat('a', 257)], + [ + false, + Message::success('The profile has been updated.'), + '0', + str_repeat('a', 256), + str_repeat('a', 256), + ], + ]; + } +}