View source
<?php
namespace Drupal\Tests\Core\Database;
use Composer\Autoload\ClassLoader;
use Drupal\Core\Database\Statement;
use Drupal\Core\Database\StatementWrapper;
use Drupal\Tests\Core\Database\Stub\StubConnection;
use Drupal\Tests\Core\Database\Stub\StubPDO;
use Drupal\Tests\Core\Database\Stub\Driver;
use Drupal\Tests\UnitTestCase;
class ConnectionTest extends UnitTestCase {
public function providerPrefixRoundTrip() {
return [
[
[
'' => 'test_',
],
'test_',
],
[
[
'fooTable' => 'foo_',
'barTable' => 'bar_',
],
[
'fooTable' => 'foo_',
'barTable' => 'bar_',
],
],
];
}
public function testPrefixRoundTrip($expected, $prefix_info) {
$mock_pdo = $this
->createMock('Drupal\\Tests\\Core\\Database\\Stub\\StubPDO');
$connection = new StubConnection($mock_pdo, []);
$reflection = new \ReflectionClass('Drupal\\Tests\\Core\\Database\\Stub\\StubConnection');
$set_prefix = $reflection
->getMethod('setPrefix');
$set_prefix
->setAccessible(TRUE);
$set_prefix
->invokeArgs($connection, [
$prefix_info,
]);
foreach ($expected as $table => $prefix) {
$this
->assertEquals($prefix, $connection
->tablePrefix($table));
}
}
public function providerTestPrefixTables() {
return [
[
'SELECT * FROM test_table',
'test_',
'SELECT * FROM {table}',
[
'',
'',
],
],
[
'SELECT * FROM "test_table"',
'test_',
'SELECT * FROM {table}',
[
'"',
'"',
],
],
[
"SELECT * FROM 'test_table'",
'test_',
'SELECT * FROM {table}',
[
"'",
"'",
],
],
[
"SELECT * FROM [test_table]",
'test_',
'SELECT * FROM {table}',
[
'[',
']',
],
],
];
}
public function testPrefixTables($expected, $prefix_info, $query, array $quote_identifier = [
'"',
'"',
]) {
$mock_pdo = $this
->createMock('Drupal\\Tests\\Core\\Database\\Stub\\StubPDO');
$connection = new StubConnection($mock_pdo, [
'prefix' => $prefix_info,
], $quote_identifier);
$this
->assertEquals($expected, $connection
->prefixTables($query));
}
public function providerGetDriverClass() {
return [
[
'nonexistent_class',
'\\',
'nonexistent_class',
],
[
'Drupal\\Tests\\Core\\Database\\Stub\\Select',
NULL,
'Select',
],
[
'Drupal\\Core\\Database\\Query\\Condition',
'Drupal\\corefake\\Driver\\Database\\corefake',
'Condition',
],
[
'Drupal\\Core\\Database\\Query\\Delete',
'Drupal\\corefake\\Driver\\Database\\corefake',
'Delete',
],
[
'Drupal\\Core\\Database\\ExceptionHandler',
'Drupal\\corefake\\Driver\\Database\\corefake',
'ExceptionHandler',
],
[
'Drupal\\Core\\Database\\Query\\Insert',
'Drupal\\corefake\\Driver\\Database\\corefake',
'Insert',
],
[
'Drupal\\Core\\Database\\Query\\Merge',
'Drupal\\corefake\\Driver\\Database\\corefake',
'Merge',
],
[
'PagerSelectExtender',
'Drupal\\corefake\\Driver\\Database\\corefake',
'PagerSelectExtender',
],
[
'Drupal\\Core\\Database\\Schema',
'Drupal\\corefake\\Driver\\Database\\corefake',
'Schema',
],
[
'SearchQuery',
'Drupal\\corefake\\Driver\\Database\\corefake',
'SearchQuery',
],
[
'Drupal\\Core\\Database\\Query\\Select',
'Drupal\\corefake\\Driver\\Database\\corefake',
'Select',
],
[
'Drupal\\Core\\Database\\Transaction',
'Drupal\\corefake\\Driver\\Database\\corefake',
'Transaction',
],
[
'TableSortExtender',
'Drupal\\corefake\\Driver\\Database\\corefake',
'TableSortExtender',
],
[
'Drupal\\Core\\Database\\Query\\Truncate',
'Drupal\\corefake\\Driver\\Database\\corefake',
'Truncate',
],
[
'Drupal\\Core\\Database\\Query\\Update',
'Drupal\\corefake\\Driver\\Database\\corefake',
'Update',
],
[
'Drupal\\Core\\Database\\Query\\Upsert',
'Drupal\\corefake\\Driver\\Database\\corefake',
'Upsert',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\Condition',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Condition',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\Delete',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Delete',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\ExceptionHandler',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'ExceptionHandler',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\Insert',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Insert',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\Merge',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Merge',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\PagerSelectExtender',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'PagerSelectExtender',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\Schema',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Schema',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\SearchQuery',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'SearchQuery',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\Select',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Select',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\TableSortExtender',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'TableSortExtender',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\Transaction',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Transaction',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\Truncate',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Truncate',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\Update',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Update',
],
[
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\Upsert',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Upsert',
],
[
'Drupal\\Core\\Database\\Query\\PagerSelectExtender',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Drupal\\Core\\Database\\Query\\PagerSelectExtender',
],
[
'\\Drupal\\Core\\Database\\Query\\PagerSelectExtender',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'\\Drupal\\Core\\Database\\Query\\PagerSelectExtender',
],
[
'Drupal\\Core\\Database\\Query\\TableSortExtender',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Drupal\\Core\\Database\\Query\\TableSortExtender',
],
[
'\\Drupal\\Core\\Database\\Query\\TableSortExtender',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'\\Drupal\\Core\\Database\\Query\\TableSortExtender',
],
[
'Drupal\\search\\SearchQuery',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'Drupal\\search\\SearchQuery',
],
[
'\\Drupal\\search\\SearchQuery',
'Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses',
'\\Drupal\\search\\SearchQuery',
],
];
}
public function testGetDriverClass($expected, $namespace, $class) {
$additional_class_loader = new ClassLoader();
$additional_class_loader
->addPsr4("Drupal\\corefake\\Driver\\Database\\corefake\\", __DIR__ . "/../../../../../tests/fixtures/database_drivers/module/corefake/src/Driver/Database/corefake");
$additional_class_loader
->addPsr4("Drupal\\corefake\\Driver\\Database\\corefakeWithAllCustomClasses\\", __DIR__ . "/../../../../../tests/fixtures/database_drivers/module/corefake/src/Driver/Database/corefakeWithAllCustomClasses");
$additional_class_loader
->register(TRUE);
$mock_pdo = $this
->createMock('Drupal\\Tests\\Core\\Database\\Stub\\StubPDO');
$connection = new StubConnection($mock_pdo, [
'namespace' => $namespace,
]);
$this
->assertEquals($expected, $connection
->getDriverClass($class));
}
public function providerSchema() {
return [
[
'Drupal\\Tests\\Core\\Database\\Stub\\Driver\\Schema',
'stub',
'Drupal\\Tests\\Core\\Database\\Stub\\Driver',
],
];
}
public function testSchema($expected, $driver, $namespace) {
$mock_pdo = $this
->createMock('Drupal\\Tests\\Core\\Database\\Stub\\StubPDO');
$connection = new StubConnection($mock_pdo, [
'namespace' => $namespace,
]);
$connection->driver = $driver;
$this
->assertInstanceOf($expected, $connection
->schema());
}
public function testDestroy() {
$this
->expectDeprecation('Drupal\\Core\\Database\\Connection::destroy() is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Move custom database destruction logic to __destruct(). See https://www.drupal.org/node/3142866');
$mock_pdo = $this
->createMock('Drupal\\Tests\\Core\\Database\\Stub\\StubPDO');
$connection = new StubConnection($mock_pdo, [
'namespace' => 'Drupal\\Tests\\Core\\Database\\Stub\\Driver',
]);
$this
->assertInstanceOf('Drupal\\Tests\\Core\\Database\\Stub\\Driver\\Schema', $connection
->schema());
$connection
->destroy();
$reflected_schema = (new \ReflectionObject($connection))
->getProperty('schema');
$reflected_schema
->setAccessible(TRUE);
$this
->assertNull($reflected_schema
->getValue($connection));
}
public function testDestructBcLayer() {
$this
->expectDeprecation('Drupal\\Core\\Database\\Connection::destroy() is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Move custom database destruction logic to __destruct(). See https://www.drupal.org/node/3142866');
$mock_pdo = $this
->createMock(StubPDO::class);
$fake_connection = new class($mock_pdo, [
'namespace' => Driver::class,
]) extends StubConnection {
public function destroy() {
parent::destroy();
}
};
$fake_connection = NULL;
}
public function providerMakeComments() {
return [
[
'/* */ ',
[
'',
],
],
[
'/* Exploit * / DROP TABLE node. -- */ ',
[
'Exploit * / DROP TABLE node; --',
],
],
[
'/* Exploit * / DROP TABLE node. --. another comment */ ',
[
'Exploit * / DROP TABLE node; --',
'another comment',
],
],
];
}
public function testMakeComments($expected, $comment_array) {
$mock_pdo = $this
->createMock('Drupal\\Tests\\Core\\Database\\Stub\\StubPDO');
$connection = new StubConnection($mock_pdo, []);
$this
->assertEquals($expected, $connection
->makeComment($comment_array));
}
public function providerFilterComments() {
return [
[
'',
'',
],
[
'Exploit * / DROP TABLE node. --',
'Exploit * / DROP TABLE node; --',
],
[
'Exploit * / DROP TABLE node. --',
'Exploit */ DROP TABLE node; --',
],
];
}
public function testFilterComments($expected, $comment) {
$mock_pdo = $this
->createMock('Drupal\\Tests\\Core\\Database\\Stub\\StubPDO');
$connection = new StubConnection($mock_pdo, []);
$reflection = new \ReflectionClass('Drupal\\Tests\\Core\\Database\\Stub\\StubConnection');
$filter_comment = $reflection
->getMethod('filterComment');
$filter_comment
->setAccessible(TRUE);
$this
->assertEquals($expected, $filter_comment
->invokeArgs($connection, [
$comment,
]));
}
public function providerEscapeTables() {
return [
[
'nocase',
'nocase',
],
[
'camelCase',
'camelCase',
],
[
'backtick',
'`backtick`',
[
'`',
'`',
],
],
[
'brackets',
'[brackets]',
[
'[',
']',
],
],
[
'camelCase',
'"camelCase"',
],
[
'camelCase',
'camel/Case',
],
[
'camelCase.nocase.nocase',
'camelCase.nocase.nocase',
],
[
'nocase.camelCase.nocase',
'nocase.camelCase.nocase',
],
[
'nocase.nocase.camelCase',
'nocase.nocase.camelCase',
],
[
'camelCase.camelCase.camelCase',
'camelCase.camelCase.camelCase',
],
];
}
public function testEscapeTable($expected, $name, array $identifier_quote = [
'"',
'"',
]) {
$mock_pdo = $this
->createMock(StubPDO::class);
$connection = new StubConnection($mock_pdo, [], $identifier_quote);
$this
->assertEquals($expected, $connection
->escapeTable($name));
}
public function providerEscapeAlias() {
return [
[
'!nocase!',
'nocase',
[
'!',
'!',
],
],
[
'`backtick`',
'backtick',
[
'`',
'`',
],
],
[
'nocase',
'nocase',
[
'',
'',
],
],
[
'[brackets]',
'brackets',
[
'[',
']',
],
],
[
'"camelCase"',
'"camelCase"',
],
[
'"camelCase"',
'camelCase',
],
[
'"camelCase"',
'camel.Case',
],
];
}
public function testEscapeAlias($expected, $name, array $identifier_quote = [
'"',
'"',
]) {
$mock_pdo = $this
->createMock(StubPDO::class);
$connection = new StubConnection($mock_pdo, [], $identifier_quote);
$this
->assertEquals($expected, $connection
->escapeAlias($name));
}
public function providerEscapeFields() {
return [
[
'/title/',
'title',
[
'/',
'/',
],
],
[
'`backtick`',
'backtick',
[
'`',
'`',
],
],
[
'test.title',
'test.title',
[
'',
'',
],
],
[
'"isDefaultRevision"',
'isDefaultRevision',
],
[
'"isDefaultRevision"',
'"isDefaultRevision"',
],
[
'"entity_test"."isDefaultRevision"',
'entity_test.isDefaultRevision',
],
[
'"entity_test"."isDefaultRevision"',
'"entity_test"."isDefaultRevision"',
],
[
'"entityTest"."isDefaultRevision"',
'"entityTest"."isDefaultRevision"',
],
[
'"entityTest"."isDefaultRevision"',
'entityTest.isDefaultRevision',
],
[
'[entityTest].[isDefaultRevision]',
'entityTest.isDefaultRevision',
[
'[',
']',
],
],
];
}
public function testEscapeField($expected, $name, array $identifier_quote = [
'"',
'"',
]) {
$mock_pdo = $this
->createMock(StubPDO::class);
$connection = new StubConnection($mock_pdo, [], $identifier_quote);
$this
->assertEquals($expected, $connection
->escapeField($name));
}
public function providerEscapeDatabase() {
return [
[
'/name/',
'name',
[
'/',
'/',
],
],
[
'`backtick`',
'backtick',
[
'`',
'`',
],
],
[
'testname',
'test.name',
[
'',
'',
],
],
[
'"name"',
'name',
],
[
'[name]',
'name',
[
'[',
']',
],
],
];
}
public function testEscapeDatabase($expected, $name, array $identifier_quote = [
'"',
'"',
]) {
$mock_pdo = $this
->createMock(StubPDO::class);
$connection = new StubConnection($mock_pdo, [], $identifier_quote);
$this
->assertEquals($expected, $connection
->escapeDatabase($name));
}
public function testIdentifierQuotesDeprecation() {
$this
->expectDeprecation('In drupal:10.0.0 not setting the $identifierQuotes property in the concrete Connection class will result in an RuntimeException. See https://www.drupal.org/node/2986894');
$mock_pdo = $this
->createMock(StubPDO::class);
new StubConnection($mock_pdo, [], NULL);
}
public function testIdentifierQuotesAssertCount() {
$this
->expectException(\AssertionError::class);
$this
->expectExceptionMessage('\\Drupal\\Core\\Database\\Connection::$identifierQuotes must contain 2 string values');
$mock_pdo = $this
->createMock(StubPDO::class);
new StubConnection($mock_pdo, [], [
'"',
]);
}
public function testIdentifierQuotesAssertString() {
$this
->expectException(\AssertionError::class);
$this
->expectExceptionMessage('\\Drupal\\Core\\Database\\Connection::$identifierQuotes must contain 2 string values');
$mock_pdo = $this
->createMock(StubPDO::class);
new StubConnection($mock_pdo, [], [
0,
'1',
]);
}
public function testNamespaceDefault() {
$mock_pdo = $this
->createMock(StubPDO::class);
$connection = new StubConnection($mock_pdo, []);
$this
->assertSame('Drupal\\Tests\\Core\\Database\\Stub', $connection
->getConnectionOptions()['namespace']);
}
public function testStatementDeprecation() {
if (PHP_VERSION_ID >= 80000) {
$this
->markTestSkipped('Drupal\\Core\\Database\\Statement is incompatible with PHP 8.0. Remove in https://www.drupal.org/node/3177490');
}
$this
->expectDeprecation('\\Drupal\\Core\\Database\\Statement is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Database drivers should use or extend StatementWrapper instead, and encapsulate client-level statement objects. See https://www.drupal.org/node/3177488');
$mock_statement = $this
->getMockBuilder(Statement::class)
->disableOriginalConstructor()
->getMock();
}
public function testQueryTrim($expected, $query, $options) {
$mock_pdo = $this
->getMockBuilder(StubPdo::class)
->setMethods([
'execute',
'prepare',
'setAttribute',
])
->getMock();
$mock_statement = $this
->getMockBuilder(StatementWrapper::class)
->disableOriginalConstructor()
->getMock();
$mock_pdo
->expects($this
->once())
->method('prepare')
->with($expected)
->willReturn($mock_statement);
$connection = new StubConnection($mock_pdo, []);
$connection
->query($query, [], $options);
}
public function provideQueriesToTrim() {
return [
'remove_non_breaking_space' => [
'SELECT * FROM test',
"",
[],
],
'remove_ordinary_space' => [
'SELECT * FROM test',
'SELECT * FROM test ',
[],
],
'remove_semicolon' => [
'SELECT * FROM test',
'SELECT * FROM test;',
[],
],
'keep_trailing_semicolon' => [
'SELECT * FROM test;',
'SELECT * FROM test;',
[
'allow_delimiter_in_query' => TRUE,
],
],
'remove_semicolon_with_whitespace' => [
'SELECT * FROM test',
'SELECT * FROM test; ',
[],
],
'keep_trailing_semicolon_with_whitespace' => [
'SELECT * FROM test;',
'SELECT * FROM test; ',
[
'allow_delimiter_in_query' => TRUE,
],
],
];
}
public function testLegacyDatabaseDriverInRootDriversDirectory() {
$this
->expectDeprecation('Support for database drivers located in the "drivers/lib/Drupal/Driver/Database" directory is deprecated in drupal:9.1.0 and is removed in drupal:10.0.0. Contributed and custom database drivers should be provided by modules and use the namespace "Drupal\\MODULE_NAME\\Driver\\Database\\DRIVER_NAME". See https://www.drupal.org/node/3123251');
$namespace = 'Drupal\\Driver\\Database\\Stub';
$mock_pdo = $this
->createMock(StubPDO::class);
$connection = new StubConnection($mock_pdo, [
'namespace' => $namespace,
], [
'"',
'"',
]);
$this
->assertEquals($namespace, $connection
->getConnectionOptions()['namespace']);
}
public function testPdoStatementClass() {
if (PHP_VERSION_ID >= 80000) {
$this
->markTestSkipped('Drupal\\Core\\Database\\Statement is incompatible with PHP 8.0. Remove in https://www.drupal.org/node/3177490');
}
$this
->expectDeprecation('\\Drupal\\Core\\Database\\Connection::$statementClass is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Database drivers should use or extend StatementWrapper instead, and encapsulate client-level statement objects. See https://www.drupal.org/node/3177488');
$mock_pdo = $this
->createMock(StubPDO::class);
new StubConnection($mock_pdo, [
'namespace' => 'Drupal\\Tests\\Core\\Database\\Stub\\Driver',
], [
'"',
'"',
], Statement::class);
}
}