phpmyadmin/tests/unit/Table/TableTest.php
Maurício Meneghini Fauth c6c9aeb678
Merge #19124 - Refactoring move copy
The goal of this was to partition the big method into smaller easier to
understand chunks and get rid of globals. This code is still far from
perfect but I have no idea how to proceed further right now.

Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
2024-05-10 11:13:57 -03:00

1550 lines
46 KiB
PHP

<?php
declare(strict_types=1);
namespace PhpMyAdmin\Tests\Table;
use PhpMyAdmin\Config;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\ConfigStorage\RelationParameters;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Dbal\ConnectionType;
use PhpMyAdmin\ListDatabase;
use PhpMyAdmin\Query\Cache;
use PhpMyAdmin\SqlParser\Context;
use PhpMyAdmin\Table\MoveMode;
use PhpMyAdmin\Table\MoveScope;
use PhpMyAdmin\Table\Table;
use PhpMyAdmin\Table\TableMover;
use PhpMyAdmin\Table\UiProperty;
use PhpMyAdmin\Tests\AbstractTestCase;
use PhpMyAdmin\Tests\FieldHelper;
use PhpMyAdmin\Tests\Stubs\DbiDummy;
use PhpMyAdmin\Tests\Stubs\DummyResult;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use ReflectionProperty;
use const MYSQLI_TYPE_STRING;
#[CoversClass(Table::class)]
class TableTest extends AbstractTestCase
{
private DatabaseInterface&MockObject $mockedDbi;
/**
* Configures environment
*/
protected function setUp(): void
{
parent::setUp();
/**
* SET these to avoid undefined index error
*/
$config = Config::getInstance();
$config->selectedServer['DisableIS'] = false;
$config->settings['MaxExactCount'] = 100;
$config->settings['MaxExactCountViews'] = 100;
$config->selectedServer['pmadb'] = 'pmadb';
$GLOBALS['sql_auto_increment'] = true;
$GLOBALS['sql_if_not_exists'] = true;
$GLOBALS['sql_drop_table'] = true;
$config->selectedServer['table_uiprefs'] = 'pma__table_uiprefs';
$sqlIsViewTrue = 'SELECT 1'
. ' FROM information_schema.VIEWS'
. ' WHERE TABLE_SCHEMA = \'PMA\''
. ' AND TABLE_NAME = \'PMA_BookMark\'';
$sqlIsViewFalse = 'SELECT 1'
. ' FROM information_schema.VIEWS'
. ' WHERE TABLE_SCHEMA = \'PMA\''
. ' AND TABLE_NAME = \'PMA_BookMark_2\'';
$sqlIsUpdatableViewTrue = 'SELECT 1'
. ' FROM information_schema.VIEWS'
. ' WHERE TABLE_SCHEMA = \'PMA\''
. ' AND TABLE_NAME = \'PMA_BookMark\''
. ' AND IS_UPDATABLE = \'YES\'';
$sqlIsUpdatableViewFalse = 'SELECT 1'
. ' FROM information_schema.VIEWS'
. ' WHERE TABLE_SCHEMA = \'PMA\''
. ' AND TABLE_NAME = \'PMA_BookMark_2\''
. ' AND IS_UPDATABLE = \'YES\'';
$sqlAnalyzeStructureTrue = 'SELECT COLUMN_NAME, DATA_TYPE'
. ' FROM information_schema.COLUMNS'
. ' WHERE TABLE_SCHEMA = \'PMA\''
. ' AND TABLE_NAME = \'PMA_BookMark\'';
$sqlCopyData = 'SELECT 1'
. ' FROM information_schema.VIEWS'
. ' WHERE TABLE_SCHEMA = \'PMA_new\''
. ' AND TABLE_NAME = \'PMA_BookMark_new\'';
$getUniqueColumnsSql = 'SHOW INDEXES FROM `PMA`.`PMA_BookMark`';
$fetchResult = [
[
$sqlAnalyzeStructureTrue,
null,
null,
ConnectionType::User,
[['COLUMN_NAME' => 'COLUMN_NAME', 'DATA_TYPE' => 'DATA_TYPE']],
],
[
$getUniqueColumnsSql . ' WHERE (Non_unique = 0)',
['Key_name', null],
'Column_name',
ConnectionType::User,
[['index1'], ['index3'], ['index5']],
],
[
$getUniqueColumnsSql,
'Column_name',
'Column_name',
ConnectionType::User,
['column1', 'column3', 'column5', 'ACCESSIBLE', 'ADD', 'ALL'],
],
[
'SHOW COLUMNS FROM `PMA`.`PMA_BookMark`',
'Field',
'Field',
ConnectionType::User,
['column1', 'column3', 'column5', 'ACCESSIBLE', 'ADD', 'ALL'],
],
[
'SHOW COLUMNS FROM `PMA`.`PMA_BookMark`',
null,
null,
ConnectionType::User,
[
[
'Field' => 'COLUMN_NAME1',
'Type' => 'INT(10)',
'Null' => 'NO',
'Key' => '',
'Default' => null,
'Extra' => '',
],
[
'Field' => 'COLUMN_NAME2',
'Type' => 'INT(10)',
'Null' => 'YES',
'Key' => '',
'Default' => null,
'Extra' => 'STORED GENERATED',
],
],
],
[
'SHOW TRIGGERS FROM `PMA` LIKE \'PMA_BookMark\';',
null,
null,
ConnectionType::User,
[
[
'Trigger' => 'name1',
'Event' => 'INSERT',
'Table' => 'PMA_BookMark',
'Timing' => 'AFTER',
'Statement' => 'BEGIN END',
'Definer' => 'test_user@localhost',
],
[
'Trigger' => 'name2',
'Event' => 'INSERT',
'Table' => 'PMA_BookMark',
'Timing' => 'AFTER',
'Statement' => 'BEGIN END',
'Definer' => 'test_user@localhost',
],
[
'Trigger' => 'name3',
'Event' => 'INSERT',
'Table' => 'PMA_BookMark',
'Timing' => 'AFTER',
'Statement' => 'BEGIN END',
'Definer' => 'test_user@localhost',
],
],
],
[
'SHOW TRIGGERS FROM `PMA` LIKE \'PMA_.BookMark\';',
null,
null,
ConnectionType::User,
[
[
'Trigger' => 'name1',
'Event' => 'INSERT',
'Table' => 'PMA_.BookMark',
'Timing' => 'AFTER',
'Statement' => 'BEGIN END',
'Definer' => 'test_user@localhost',
],
[
'Trigger' => 'name2',
'Event' => 'INSERT',
'Table' => 'PMA_.BookMark',
'Timing' => 'AFTER',
'Statement' => 'BEGIN END',
'Definer' => 'test_user@localhost',
],
[
'Trigger' => 'name3',
'Event' => 'INSERT',
'Table' => 'PMA_.BookMark',
'Timing' => 'AFTER',
'Statement' => 'BEGIN END',
'Definer' => 'test_user@localhost',
],
],
],
[
'SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE, ACTION_TIMING, '
. 'ACTION_STATEMENT, EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE, DEFINER FROM '
. "information_schema.TRIGGERS WHERE EVENT_OBJECT_SCHEMA COLLATE utf8_bin= 'PMA' "
. "AND EVENT_OBJECT_TABLE COLLATE utf8_bin = 'PMA_BookMark';",
null,
null,
ConnectionType::User,
[
[],
],
],
[
'SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE, ACTION_TIMING, '
. 'ACTION_STATEMENT, EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE, DEFINER FROM '
. "information_schema.TRIGGERS WHERE EVENT_OBJECT_SCHEMA COLLATE utf8_bin= 'aa' "
. "AND EVENT_OBJECT_TABLE COLLATE utf8_bin = 'ad';",
null,
null,
ConnectionType::User,
[
[],
],
],
[
'SHOW COLUMNS FROM `aa`.`ad`',
null,
null,
ConnectionType::User,
[],
],
];
$fetchValue = [
[$sqlIsViewTrue, 0, ConnectionType::User, 'PMA_BookMark'],
[$sqlCopyData, 0, ConnectionType::User, false],
[$sqlIsViewFalse, 0, ConnectionType::User, false],
[$sqlIsUpdatableViewTrue, 0, ConnectionType::User, 'PMA_BookMark'],
[$sqlIsUpdatableViewFalse, 0, ConnectionType::User, false],
[
"SELECT 1 FROM information_schema.VIEWS WHERE TABLE_SCHEMA = 'aa' AND TABLE_NAME = 'ad'",
0,
ConnectionType::User,
'ad',
],
[
"SELECT 1 FROM information_schema.VIEWS WHERE TABLE_SCHEMA = 'bb' AND TABLE_NAME = 'ad'",
0,
ConnectionType::User,
false,
],
];
$resultStub = $this->createMock(DummyResult::class);
$dbi = $this->getMockBuilder(DatabaseInterface::class)
->disableOriginalConstructor()
->getMock();
$databaseList = self::createStub(ListDatabase::class);
$databaseList->method('exists')->willReturn(true);
$dbi->expects(self::any())->method('getDatabaseList')->willReturn($databaseList);
$dbi->expects(self::any())->method('fetchResult')
->willReturnMap($fetchResult);
$dbi->expects(self::any())->method('fetchValue')
->willReturnMap($fetchValue);
$cache = new Cache();
$dbi->expects(self::any())->method('getCache')
->willReturn($cache);
$databases = [];
$databaseName = 'PMA';
$databases[$databaseName]['SCHEMA_TABLES'] = 1;
$databases[$databaseName]['SCHEMA_TABLE_ROWS'] = 3;
$databases[$databaseName]['SCHEMA_DATA_LENGTH'] = 5;
$databases[$databaseName]['SCHEMA_MAX_DATA_LENGTH'] = 10;
$databases[$databaseName]['SCHEMA_INDEX_LENGTH'] = 10;
$databases[$databaseName]['SCHEMA_LENGTH'] = 10;
$dbi->expects(self::any())->method('getTablesFull')
->willReturn($databases);
$dbi->expects(self::any())->method('query')
->willReturn($resultStub);
$dbi->expects(self::any())->method('insertId')
->willReturn(10);
$resultStub->expects(self::any())->method('fetchAssoc')
->willReturn([]);
$value = ['Auto_increment' => 'Auto_increment'];
$dbi->expects(self::any())->method('fetchSingleRow')
->willReturn($value);
$resultStub->expects(self::any())->method('fetchRow')
->willReturn([]);
$dbi->expects(self::any())->method('quoteString')
->willReturnCallback(static fn (string $string): string => "'" . $string . "'");
DatabaseInterface::$instance = $dbi;
$this->mockedDbi = $dbi;
}
protected function tearDown(): void
{
parent::tearDown();
DatabaseInterface::$instance = null;
}
/**
* Test for constructor
*/
public function testConstruct(): void
{
$table = new Table('PMA_BookMark', 'PMA', $this->mockedDbi);
self::assertSame(
'PMA_BookMark',
$table->__toString(),
);
self::assertSame(
'PMA_BookMark',
$table->getName(),
);
self::assertSame(
'PMA',
$table->getDbName(),
);
self::assertSame(
'PMA.PMA_BookMark',
$table->getFullName(),
);
}
/**
* Test getName & getDbName
*/
public function testGetName(): void
{
$table = new Table('table1', 'pma_test', $this->mockedDbi);
self::assertSame(
'table1',
$table->getName(),
);
self::assertSame(
'`table1`',
$table->getName(true),
);
self::assertSame(
'pma_test',
$table->getDbName(),
);
self::assertSame(
'`pma_test`',
$table->getDbName(true),
);
}
/**
* Test getLastError & getLastMessage
*/
public function testGetLastErrorAndMessage(): void
{
$table = new Table('table1', 'pma_test', $this->mockedDbi);
$table->errors[] = 'error1';
$table->errors[] = 'error2';
$table->errors[] = 'error3';
$table->messages[] = 'messages1';
$table->messages[] = 'messages2';
$table->messages[] = 'messages3';
self::assertSame(
'error3',
$table->getLastError(),
);
self::assertSame(
'messages3',
$table->getLastMessage(),
);
$table->errors = [];
self::assertSame(
'',
$table->getLastError(),
);
$table->messages = [];
self::assertSame(
'',
$table->getLastMessage(),
);
}
/**
* Test name validation
*
* @param string $name name to test
* @param bool $result expected result
* @param bool $isBackquoted is backquoted
*/
#[DataProvider('dataValidateName')]
public function testValidateName(string $name, bool $result, bool $isBackquoted = false): void
{
self::assertSame(
$result,
Table::isValidName($name, $isBackquoted),
);
}
/** @return array<array{0: string, 1: bool, 2?: bool}> */
public static function dataValidateName(): array
{
return [
['test', true],
['te/st', false],
['te.st', false],
['te\\st', false],
['te st', false],
[' te st', true, true],
['test ', false],
['te.st', false],
['test ', false, true],
['te.st ', false, true],
];
}
/**
* Test for isView
*/
public function testIsView(): void
{
$table = new Table('', '', $this->mockedDbi);
self::assertFalse(
$table->isView(),
);
//validate that it is the same as DBI fetchResult
$table = new Table('PMA_BookMark', 'PMA', $this->mockedDbi);
self::assertTrue(
$table->isView(),
);
$table = new Table('PMA_BookMark_2', 'PMA', $this->mockedDbi);
self::assertFalse(
$table->isView(),
);
}
/**
* Test for generateFieldSpec
*/
public function testGenerateFieldSpec(): void
{
//type is BIT
$name = 'PMA_name';
$type = 'BIT';
$length = '12';
$attribute = 'PMA_attribute';
$collation = 'PMA_collation';
$null = 'YES';
$defaultType = 'USER_DEFINED';
$defaultValue = '12';
$extra = 'AUTO_INCREMENT';
$comment = 'PMA_comment';
$virtuality = '';
$expression = '';
$moveTo = '-first';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
self::assertSame(
'`PMA_name` BIT(12) PMA_attribute NULL DEFAULT b\'10\' AUTO_INCREMENT COMMENT \'PMA_comment\' FIRST',
$query,
);
//type is DOUBLE
$type = 'DOUBLE';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
self::assertSame(
'`PMA_name` DOUBLE(12) PMA_attribute NULL DEFAULT \'12\' AUTO_INCREMENT COMMENT \'PMA_comment\' FIRST',
$query,
);
//type is BOOLEAN
$type = 'BOOLEAN';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
self::assertSame(
'`PMA_name` BOOLEAN PMA_attribute NULL DEFAULT TRUE AUTO_INCREMENT COMMENT \'PMA_comment\' FIRST',
$query,
);
//$default_type is NULL
$defaultType = 'NULL';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
self::assertSame(
'`PMA_name` BOOLEAN PMA_attribute NULL DEFAULT NULL AUTO_INCREMENT COMMENT \'PMA_comment\' FIRST',
$query,
);
//$default_type is CURRENT_TIMESTAMP
$defaultType = 'CURRENT_TIMESTAMP';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
self::assertSame(
'`PMA_name` BOOLEAN PMA_attribute NULL DEFAULT CURRENT_TIMESTAMP '
. "AUTO_INCREMENT COMMENT 'PMA_comment' FIRST",
$query,
);
//$default_type is current_timestamp()
$defaultType = 'current_timestamp()';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
self::assertSame(
'`PMA_name` BOOLEAN PMA_attribute NULL DEFAULT current_timestamp() '
. "AUTO_INCREMENT COMMENT 'PMA_comment' FIRST",
$query,
);
// $type is 'TIMESTAMP(3), $default_type is CURRENT_TIMESTAMP(3)
$type = 'TIMESTAMP';
$length = '3';
$extra = '';
$defaultType = 'CURRENT_TIMESTAMP';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
self::assertSame(
'`PMA_name` TIMESTAMP(3) PMA_attribute NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT \'PMA_comment\' FIRST',
$query,
);
$type = 'TIMESTAMP';
$length = '';
$extra = '';
$defaultType = 'USER_DEFINED';
$defaultValue = '\'0000-00-00 00:00:00\'';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
self::assertSame(
'`PMA_name` TIMESTAMP PMA_attribute NULL DEFAULT \'0000-00-00 00:00:00\' COMMENT \'PMA_comment\' FIRST',
$query,
);
$type = 'TIMESTAMP';
$length = '';
$extra = '';
$defaultType = 'USER_DEFINED';
$defaultValue = '\'0000-00-00 00:00:00.0\'';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
self::assertSame(
'`PMA_name` TIMESTAMP PMA_attribute NULL DEFAULT \'0000-00-00 00:00:00.0\' COMMENT \'PMA_comment\' FIRST',
$query,
);
$type = 'TIMESTAMP';
$length = '';
$extra = '';
$defaultType = 'USER_DEFINED';
$defaultValue = '\'0000-00-00 00:00:00.000000\'';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
self::assertSame(
'`PMA_name` TIMESTAMP PMA_attribute NULL DEFAULT \'0000-00-00 00:00:00.000000\' '
. "COMMENT 'PMA_comment' FIRST",
$query,
);
//$default_type is UUID
$type = 'UUID';
$defaultType = 'UUID';
$moveTo = '';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
'',
$virtuality,
$expression,
$moveTo,
);
self::assertSame('`PMA_name` UUID PMA_attribute NULL DEFAULT uuid()', $query);
//$default_type is uuid()
$type = 'UUID';
$defaultType = 'uuid()';
$moveTo = '';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
'',
$virtuality,
$expression,
$moveTo,
);
self::assertSame('`PMA_name` UUID PMA_attribute NULL DEFAULT uuid()', $query);
//$default_type is NONE
$type = 'BOOLEAN';
$defaultType = 'NONE';
$extra = 'INCREMENT';
$moveTo = '-first';
$query = Table::generateFieldSpec(
$name,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
self::assertSame('`PMA_name` BOOLEAN PMA_attribute NULL INCREMENT COMMENT \'PMA_comment\' FIRST', $query);
$defaultType = 'NONE';
$moveTo = '-first';
$query = Table::generateFieldSpec(
'ids',
'INT',
'11',
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
'AUTO_INCREMENT',
$comment,
$virtuality,
$expression,
$moveTo,
['id'],
'id',
);
self::assertSame('`ids` INT(11) PMA_attribute NULL AUTO_INCREMENT COMMENT \'PMA_comment\' FIRST', $query);
$defaultType = 'NONE';
$moveTo = '-first';
$query = Table::generateFieldSpec(
'ids',
'INT',
'11',
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
'AUTO_INCREMENT',
$comment,
$virtuality,
$expression,
$moveTo,
['othercol'],
'id',
);
// Add primary key for AUTO_INCREMENT if missing
self::assertSame(
'`ids` INT(11) PMA_attribute NULL AUTO_INCREMENT '
. "COMMENT 'PMA_comment' FIRST, add PRIMARY KEY (`ids`)",
$query,
);
$defaultType = 'NONE';
$moveTo = '-first';
$query = Table::generateFieldSpec(
'id',
'INT',
'11',
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
'DEF',
$comment,
$virtuality,
$expression,
$moveTo,
['id'],
'id',
);
// Do not add PK
self::assertSame('`id` INT(11) PMA_attribute NULL DEF COMMENT \'PMA_comment\' FIRST', $query);
$defaultType = 'NONE';
$moveTo = '-first';
$query = Table::generateFieldSpec(
'ids',
'INT',
'11',
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
'DEF',
$comment,
$virtuality,
$expression,
$moveTo,
['id'],
'id',
);
// Do not add PK
self::assertSame('`ids` INT(11) PMA_attribute NULL DEF COMMENT \'PMA_comment\' FIRST', $query);
$defaultType = 'NONE';
$moveTo = '-first';
$query = Table::generateFieldSpec(
'ids',
'INT',
'11',
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
'DEF',
$comment,
$virtuality,
$expression,
$moveTo,
['ids'],
'id',
);
// Add it beaucause it is missing
self::assertSame(
'`ids` INT(11) PMA_attribute NULL DEF COMMENT \'PMA_comment\' FIRST, add PRIMARY KEY (`ids`)',
$query,
);
$defaultType = 'NONE';
$moveTo = '-first';
$query = Table::generateFieldSpec(
'ids',
'INT',
'11',
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
'USER_DEFINED',
$comment,
'VIRTUAL',
'1',
$moveTo,
['othercol'],
'id',
);
// Do not add PK since it is not a AUTO_INCREMENT
self::assertSame(
'`ids` INT(11) PMA_attribute AS (1) VIRTUAL NULL USER_DEFINED COMMENT \'PMA_comment\' FIRST',
$query,
);
}
/**
* Test for duplicateInfo
*/
public function testDuplicateInfo(): void
{
$getFields = ['filed0', 'field6'];
$whereFields = ['field2', 'filed5'];
$newFields = ['field3', 'filed4'];
$relationParameters = RelationParameters::fromArray([
'db' => 'PMA_db',
'relwork' => true,
'relation' => 'relation',
]);
(new ReflectionProperty(Relation::class, 'cache'))->setValue(null, $relationParameters);
$object = new TableMover($this->mockedDbi, new Relation($this->mockedDbi));
$ret = $object->duplicateInfo('relwork', 'relation', $getFields, $whereFields, $newFields);
self::assertSame(-1, $ret);
}
/**
* Test for isUpdatableView
*/
public function testIsUpdatableView(): void
{
$table = new Table('', '', $this->mockedDbi);
self::assertFalse(
$table->isUpdatableView(),
);
//validate that it is the same as DBI fetchResult
$table = new Table('PMA_BookMark', 'PMA', $this->mockedDbi);
self::assertTrue(
$table->isUpdatableView(),
);
$table = new Table('PMA_BookMark_2', 'PMA', $this->mockedDbi);
self::assertFalse(
$table->isUpdatableView(),
);
}
/**
* Test for isMerge -- when there's no ENGINE info cached
*/
public function testIsMergeCase1(): void
{
$tableObj = new Table('PMA_BookMark', 'PMA', $this->mockedDbi);
self::assertFalse(
$tableObj->isMerge(),
);
}
/**
* Test for isMerge -- when ENGINE info is MERGE
*/
public function testIsMergeCase2(): void
{
$this->mockedDbi->getCache()->cacheTableValue('PMA', 'PMA_BookMark', 'ENGINE', 'MERGE');
$tableObj = new Table('PMA_BookMark', 'PMA', $this->mockedDbi);
self::assertTrue(
$tableObj->isMerge(),
);
}
/**
* Test for isMerge -- when ENGINE info is MRG_MYISAM
*/
public function testIsMergeCase3(): void
{
$this->mockedDbi->getCache()->cacheTableValue('PMA', 'PMA_BookMark', 'ENGINE', 'MRG_MYISAM');
$tableObj = new Table('PMA_BookMark', 'PMA', $this->mockedDbi);
self::assertTrue(
$tableObj->isMerge(),
);
}
/**
* Test for Table::isMerge -- when ENGINE info is ISDB
*/
public function testIsMergeCase4(): void
{
$tableObj = new Table('PMA_BookMark', 'PMA', $this->mockedDbi);
self::assertFalse(
$tableObj->isMerge(),
);
}
/**
* Test for generateAlter
*/
public function testGenerateAlter(): void
{
//parameter
$oldcol = 'name';
$newcol = 'new_name';
$type = 'VARCHAR';
$length = '2';
$attribute = 'new_name';
$collation = 'charset1';
$null = 'YES';
$defaultType = 'USER_DEFINED';
$defaultValue = 'VARCHAR';
$extra = 'AUTO_INCREMENT';
$comment = 'PMA comment';
$virtuality = '';
$expression = '';
$moveTo = 'new_name';
$result = Table::generateAlter(
$oldcol,
$newcol,
$type,
$length,
$attribute,
$collation,
$null,
$defaultType,
$defaultValue,
$extra,
$comment,
$virtuality,
$expression,
$moveTo,
);
$expect = '`name` `new_name` VARCHAR(2) new_name CHARACTER SET '
. "charset1 NULL DEFAULT 'VARCHAR' "
. "AUTO_INCREMENT COMMENT 'PMA comment' AFTER `new_name`";
self::assertSame($expect, $result);
}
/**
* Test for rename
*/
public function testRename(): void
{
Config::getInstance()->selectedServer['DisableIS'] = true;
$table = 'PMA_BookMark';
$db = 'PMA';
$this->mockedDbi->expects(self::any())->method('tryQuery')->willReturn($this->createMock(DummyResult::class));
$table = new Table($table, $db, $this->mockedDbi);
//rename to same name
$tableNew = 'PMA_BookMark';
$result = $table->rename($tableNew);
self::assertTrue($result);
//isValidName
//space in table name
$tableNew = 'PMA_BookMark ';
$result = $table->rename($tableNew);
self::assertFalse($result);
//empty name
$tableNew = '';
$result = $table->rename($tableNew);
self::assertFalse($result);
//dot in table name
$tableNew = 'PMA_.BookMark';
$result = $table->rename($tableNew);
self::assertTrue($result);
//message
self::assertSame(
'Table PMA_BookMark has been renamed to PMA_.BookMark.',
$table->getLastMessage(),
);
$tableNew = 'PMA_BookMark_new';
$dbNew = 'PMA_new';
$result = $table->rename($tableNew, $dbNew);
self::assertTrue($result);
//message
self::assertSame(
'Table PMA_.BookMark has been renamed to PMA_BookMark_new.',
$table->getLastMessage(),
);
}
/**
* Test for getUniqueColumns
*/
public function testGetUniqueColumns(): void
{
$table = 'PMA_BookMark';
$db = 'PMA';
$table = new Table($table, $db, $this->mockedDbi);
$return = $table->getUniqueColumns();
$expect = ['`PMA`.`PMA_BookMark`.`index1`', '`PMA`.`PMA_BookMark`.`index3`', '`PMA`.`PMA_BookMark`.`index5`'];
self::assertSame($expect, $return);
}
/**
* Test for getIndexedColumns
*/
public function testGetIndexedColumns(): void
{
$table = 'PMA_BookMark';
$db = 'PMA';
$table = new Table($table, $db, $this->mockedDbi);
$return = $table->getIndexedColumns();
$expect = [
'`PMA`.`PMA_BookMark`.`column1`',
'`PMA`.`PMA_BookMark`.`column3`',
'`PMA`.`PMA_BookMark`.`column5`',
'`PMA`.`PMA_BookMark`.`ACCESSIBLE`',
'`PMA`.`PMA_BookMark`.`ADD`',
'`PMA`.`PMA_BookMark`.`ALL`',
];
self::assertSame($expect, $return);
}
/**
* Test for getColumnsMeta
*/
public function testGetColumnsMeta(): void
{
$dbi = $this->getMockBuilder(DatabaseInterface::class)
->disableOriginalConstructor()
->getMock();
$resultStub = $this->createMock(DummyResult::class);
$dbi->expects(self::once())
->method('tryQuery')
->with('SELECT * FROM `db`.`table` LIMIT 1')
->willReturn($resultStub);
$dummyFieldMetadata = FieldHelper::fromArray(['type' => MYSQLI_TYPE_STRING]);
$dbi->expects(self::once())
->method('getFieldsMeta')
->with($resultStub)
->willReturn([$dummyFieldMetadata]);
DatabaseInterface::$instance = $dbi;
$tableObj = new Table('table', 'db', $dbi);
self::assertSame(
$tableObj->getColumnsMeta(),
[$dummyFieldMetadata],
);
}
/**
* Tests for getSQLToCreateForeignKey() method.
*/
public function testGetSQLToCreateForeignKey(): void
{
$table = 'PMA_table';
$field = ['PMA_field1', 'PMA_field2'];
$foreignDb = 'foreignDb';
$foreignTable = 'foreignTable';
$foreignField = ['foreignField1', 'foreignField2'];
$tableObj = new Table('PMA_table', 'db', $this->mockedDbi);
$sql = $this->callFunction(
$tableObj,
Table::class,
'getSQLToCreateForeignKey',
[$table, $field, $foreignDb, $foreignTable, $foreignField],
);
$sqlExcepted = 'ALTER TABLE `PMA_table` ADD '
. 'FOREIGN KEY (`PMA_field1`, `PMA_field2`) REFERENCES '
. '`foreignDb`.`foreignTable`(`foreignField1`, `foreignField2`);';
self::assertSame($sqlExcepted, $sql);
// Exclude db name when relations are made between table in the same db
$sql = $this->callFunction(
$tableObj,
Table::class,
'getSQLToCreateForeignKey',
[$table, $field, 'db', $foreignTable, $foreignField],
);
$sqlExcepted = 'ALTER TABLE `PMA_table` ADD '
. 'FOREIGN KEY (`PMA_field1`, `PMA_field2`) REFERENCES '
. '`foreignTable`(`foreignField1`, `foreignField2`);';
self::assertSame($sqlExcepted, $sql);
}
/**
* Test for getColumns
*/
public function testGetColumns(): void
{
Context::load();
$table = 'PMA_BookMark';
$db = 'PMA';
$table = new Table($table, $db, $this->mockedDbi);
$return = $table->getColumns();
$expect = [
'`PMA`.`PMA_BookMark`.`column1`',
'`PMA`.`PMA_BookMark`.`column3`',
'`PMA`.`PMA_BookMark`.`column5`',
'`PMA`.`PMA_BookMark`.`ACCESSIBLE`',
'`PMA`.`PMA_BookMark`.`ADD`',
'`PMA`.`PMA_BookMark`.`ALL`',
];
self::assertSame($expect, $return);
$return = $table->getReservedColumnNames();
$expect = ['ACCESSIBLE', 'ADD', 'ALL'];
self::assertSame($expect, $return);
}
/**
* Test for checkIfMinRecordsExist
*/
public function testCheckIfMinRecordsExist(): void
{
$oldDbi = $this->mockedDbi;
$resultStub = $this->createMock(DummyResult::class);
$dbi = $this->getMockBuilder(DatabaseInterface::class)
->disableOriginalConstructor()
->getMock();
$dbi->expects(self::any())
->method('tryQuery')
->willReturn($resultStub);
$resultStub->expects(self::any())
->method('numRows')
->willReturn(0, 10, 200);
$dbi->expects(self::any())
->method('fetchResult')
->willReturn(
[['`one_pk`']],
[], // No Uniques found
['`one_ind`', '`sec_ind`'],
[], // No Uniques found
[], // No Indexed found
);
DatabaseInterface::$instance = $dbi;
$table = 'PMA_BookMark';
$db = 'PMA';
$tableObj = new Table($table, $db, $dbi);
// Case 1 : Check if table is non-empty
$return = $tableObj->checkIfMinRecordsExist();
self::assertTrue($return);
// Case 2 : Check if table contains at least 100
$return = $tableObj->checkIfMinRecordsExist(100);
self::assertFalse($return);
// Case 3 : Check if table contains at least 100
$return = $tableObj->checkIfMinRecordsExist(100);
self::assertTrue($return);
DatabaseInterface::$instance = $oldDbi;
}
/**
* Test for Table::countRecords
*/
public function testCountRecords(): void
{
$resultStub = $this->createMock(DummyResult::class);
$resultStub->expects(self::any())
->method('numRows')
->willReturn(20);
$dbi = clone $this->mockedDbi;
$dbi->expects(self::any())->method('tryQuery')
->willReturn($resultStub);
$table = 'PMA_BookMark';
$db = 'PMA';
$tableObj = new Table($table, $db, $dbi);
self::assertSame(
20,
$tableObj->countRecords(true),
);
}
/**
* Test for setUiProp
*/
public function testSetUiProp(): void
{
$tableName = 'PMA_BookMark';
$db = 'PMA';
$table = new Table($tableName, $db, $this->mockedDbi);
$property = UiProperty::ColumnOrder;
$value = 'UiProp_value';
$tableCreateTime = null;
$table->setUiProp($property, $value, $tableCreateTime);
//set UI prop successfully
self::assertSame($value, $table->uiprefs[$property->value]);
//removeUiProp
$table->removeUiProp($property);
$isDefineProperty = isset($table->uiprefs[$property->value]);
self::assertFalse($isDefineProperty);
//getUiProp after removeUiProp
$isDefineProperty = $table->getUiProp($property);
self::assertFalse($isDefineProperty);
}
/**
* Test for moveCopy
*/
public function testMoveCopy(): void
{
$sourceTable = 'PMA_BookMark';
$sourceDb = 'PMA';
$targetTable = 'PMA_BookMark_new';
$targetDb = 'PMA_new';
unset($GLOBALS['sql_drop_table']);
$getTableMap = [
[$targetDb, $targetTable, new Table($targetTable, $targetDb, $this->mockedDbi)],
['aa', 'ad', new Table('ad', 'aa', $this->mockedDbi)],
];
$this->mockedDbi->expects(self::any())->method('getTable')
->willReturnMap($getTableMap);
$object = new TableMover($this->mockedDbi, new Relation($this->mockedDbi));
$return = $object->moveCopy(
$sourceDb,
$sourceTable,
$targetDb,
$targetTable,
MoveScope::Move,
MoveMode::SingleTable,
true,
);
//successfully
self::assertTrue($return);
$sqlQuery = 'INSERT INTO `PMA_new`.`PMA_BookMark_new`(`COLUMN_NAME1`)'
. ' SELECT `COLUMN_NAME1` FROM '
. '`PMA`.`PMA_BookMark`';
self::assertStringContainsString($sqlQuery, $GLOBALS['sql_query']);
$sqlQuery = 'DROP VIEW `PMA`.`PMA_BookMark`';
self::assertStringContainsString($sqlQuery, $GLOBALS['sql_query']);
$return = $object->moveCopy(
$sourceDb,
$sourceTable,
$targetDb,
$targetTable,
MoveScope::DataOnly,
MoveMode::SingleTable,
true,
);
//successfully
self::assertTrue($return);
$sqlQuery = 'INSERT INTO `PMA_new`.`PMA_BookMark_new`(`COLUMN_NAME1`)'
. ' SELECT `COLUMN_NAME1` FROM '
. '`PMA`.`PMA_BookMark`';
self::assertStringContainsString($sqlQuery, $GLOBALS['sql_query']);
$sqlQuery = 'DROP VIEW `PMA`.`PMA_BookMark`';
self::assertStringNotContainsString($sqlQuery, $GLOBALS['sql_query']);
// Renaming DB with a view bug
$resultStub = $this->createMock(DummyResult::class);
$this->mockedDbi->expects(self::any())->method('tryQuery')
->willReturnMap([
[
'SHOW CREATE TABLE `aa`.`ad`',
ConnectionType::User,
DatabaseInterface::QUERY_BUFFERED,
true,
$resultStub,
],
[
'SHOW TABLE STATUS FROM `aa` WHERE Name = \'ad\'',
ConnectionType::User,
DatabaseInterface::QUERY_BUFFERED,
true,
$resultStub,
],
['USE `aa`', ConnectionType::User, DatabaseInterface::QUERY_BUFFERED, true, $resultStub],
[
'RENAME TABLE `PMA`.`PMA_BookMark` TO `PMA`.`PMA_.BookMark`;',
ConnectionType::User,
DatabaseInterface::QUERY_BUFFERED,
true,
false,
],
[
'RENAME TABLE `aa`.`ad` TO `bb`.`ad`;',
ConnectionType::User,
DatabaseInterface::QUERY_BUFFERED,
true,
false,
],
]);
$resultStub->expects(self::any())
->method('fetchRow')
->willReturn([
'ad',
'CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost`' .
' SQL SECURITY DEFINER VIEW `ad` AS select `aa`.`bb`.`ac` AS `ac` from `bb`',
'utf8mb4',
'utf8mb4_unicode_ci',
]);
$GLOBALS['sql_query'] = '';
$return = $object->moveCopy('aa', 'ad', 'bb', 'ad', MoveScope::Move, MoveMode::WholeDatabase, true);
self::assertTrue($return);
self::assertStringContainsString('DROP TABLE IF EXISTS `bb`.`ad`;', $GLOBALS['sql_query']);
self::assertStringContainsString(
'CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost`' .
' SQL SECURITY DEFINER VIEW `bb`.`ad` AS SELECT `bb`.`ac` AS `ac` FROM `bb` ;',
$GLOBALS['sql_query'],
);
self::assertStringContainsString('DROP VIEW `aa`.`ad`;', $GLOBALS['sql_query']);
}
/**
* Test for getStorageEngine
*/
public function testGetStorageEngine(): void
{
$targetTable = 'table1';
$targetDb = 'pma_test';
$extension = new DbiDummy();
$dbi = new DatabaseInterface($extension);
$tblObject = new Table($targetTable, $targetDb, $dbi);
$tblObject->getStatusInfo(null);
$expect = 'DBIDUMMY';
$tblStorageEngine = $dbi->getTable($targetDb, $targetTable)->getStorageEngine();
self::assertSame($expect, $tblStorageEngine);
}
/**
* Test for getComment
*/
public function testGetComment(): void
{
$targetTable = 'table1';
$targetDb = 'pma_test';
$extension = new DbiDummy();
$dbi = new DatabaseInterface($extension);
$tblObject = new Table($targetTable, $targetDb, $dbi);
$tblObject->getStatusInfo(null);
$expect = 'Test comment for "table1" in \'pma_test\'';
$showComment = $dbi->getTable($targetDb, $targetTable)->getComment();
self::assertSame($expect, $showComment);
}
/**
* Test for getCollation
*/
public function testGetCollation(): void
{
$targetTable = 'table1';
$targetDb = 'pma_test';
$extension = new DbiDummy();
$dbi = new DatabaseInterface($extension);
$tblObject = new Table($targetTable, $targetDb, $dbi);
$tblObject->getStatusInfo(null);
$expect = 'utf8mb4_general_ci';
$tblCollation = $dbi->getTable($targetDb, $targetTable)->getCollation();
self::assertSame($expect, $tblCollation);
}
/**
* Test for getRowFormat
*/
public function testGetRowFormat(): void
{
$targetTable = 'table1';
$targetDb = 'pma_test';
$extension = new DbiDummy();
$dbi = new DatabaseInterface($extension);
$tblObject = new Table($targetTable, $targetDb, $dbi);
$tblObject->getStatusInfo(null);
$expect = 'Redundant';
$rowFormat = $dbi->getTable($targetDb, $targetTable)->getRowFormat();
self::assertSame($expect, $rowFormat);
}
/**
* Test for getAutoIncrement
*/
public function testGetAutoIncrement(): void
{
$targetTable = 'table1';
$targetDb = 'pma_test';
$extension = new DbiDummy();
$dbi = new DatabaseInterface($extension);
$tblObject = new Table($targetTable, $targetDb, $dbi);
$tblObject->getStatusInfo(null);
$expect = '5';
$autoIncrement = $dbi->getTable($targetDb, $targetTable)->getAutoIncrement();
self::assertSame($expect, $autoIncrement);
}
/**
* Test for getCreateOptions
*/
public function testGetCreateOptions(): void
{
$targetTable = 'table1';
$targetDb = 'pma_test';
$extension = new DbiDummy();
$dbi = new DatabaseInterface($extension);
$tblObject = new Table($targetTable, $targetDb, $dbi);
$tblObject->getStatusInfo(null);
$expect = ['pack_keys' => 'DEFAULT', 'row_format' => 'REDUNDANT'];
$createOptions = $dbi->getTable($targetDb, $targetTable)->getCreateOptions();
self::assertEquals($expect, $createOptions);
}
}