mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #9651 from open-sausages/pulls/4/test-mysql-connection-collation
ENH Test coverage for MySQL connection collation
This commit is contained in:
commit
6b78428fbb
139
tests/php/ORM/MySQLPDOConnectorTest.php
Normal file
139
tests/php/ORM/MySQLPDOConnectorTest.php
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
use SilverStripe\Core\Config\Config;
|
||||||
|
use SilverStripe\ORM\Connect\MySQLDatabase;
|
||||||
|
use SilverStripe\Dev\SapphireTest;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\ORM\Tests\MySQLPDOConnectorTest\PDOConnector;
|
||||||
|
use SilverStripe\ORM\DB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @requires extension PDO
|
||||||
|
* @requires extension pdo_mysql
|
||||||
|
*/
|
||||||
|
class MySQLPDOConnectorTest extends SapphireTest implements TestOnly
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @dataProvider charsetProvider
|
||||||
|
*/
|
||||||
|
public function testConnectionCharsetControl($charset, $defaultCollation)
|
||||||
|
{
|
||||||
|
$config = DB::getConfig();
|
||||||
|
$config['driver'] = 'mysql';
|
||||||
|
$config['charset'] = $charset;
|
||||||
|
$config['database'] = 'information_schema';
|
||||||
|
Config::inst()->set(MySQLDatabase::class, 'connection_collation', $defaultCollation);
|
||||||
|
|
||||||
|
if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
|
||||||
|
return $this->markTestSkipped('The test only relevant for MySQL');
|
||||||
|
}
|
||||||
|
|
||||||
|
$connector = new PDOConnector();
|
||||||
|
$connector->connect($config);
|
||||||
|
$connection = $connector->getPDOConnection();
|
||||||
|
|
||||||
|
$cset = $connection->query('show variables like "character_set_connection"')->fetch(PDO::FETCH_NUM)[1];
|
||||||
|
$collation = $connection->query('show variables like "collation_connection"')->fetch(PDO::FETCH_NUM)[1];
|
||||||
|
|
||||||
|
$this->assertEquals($charset, $cset);
|
||||||
|
$this->assertEquals($defaultCollation, $collation);
|
||||||
|
|
||||||
|
unset($cset, $connection, $connector, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testConnectionCharsetControl
|
||||||
|
* @dataProvider charsetProvider
|
||||||
|
*/
|
||||||
|
public function testConnectionCollationControl($charset, $defaultCollation, $customCollation)
|
||||||
|
{
|
||||||
|
$config = DB::getConfig();
|
||||||
|
$config['charset'] = $charset;
|
||||||
|
$config['driver'] = 'mysql';
|
||||||
|
$config['database'] = 'information_schema';
|
||||||
|
Config::inst()->set(MySQLDatabase::class, 'connection_collation', $customCollation);
|
||||||
|
|
||||||
|
if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
|
||||||
|
return $this->markTestSkipped('The test only relevant for MySQL');
|
||||||
|
}
|
||||||
|
|
||||||
|
$connector = new PDOConnector();
|
||||||
|
$connector->connect($config);
|
||||||
|
$connection = $connector->getPDOConnection();
|
||||||
|
|
||||||
|
$cset = $connection->query('show variables like "character_set_connection"')->fetch(PDO::FETCH_NUM)[1];
|
||||||
|
$collation = $connection->query('show variables like "collation_connection"')->fetch(PDO::FETCH_NUM)[1];
|
||||||
|
|
||||||
|
$this->assertEquals($charset, $cset);
|
||||||
|
$this->assertEquals($customCollation, $collation);
|
||||||
|
|
||||||
|
unset($cset, $connection, $connector, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function charsetProvider()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['ascii', 'ascii_general_ci', 'ascii_bin'],
|
||||||
|
['utf8', 'utf8_general_ci', 'utf8_unicode_520_ci'],
|
||||||
|
['utf8mb4', 'utf8mb4_general_ci', 'utf8mb4_unicode_520_ci']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUtf8mb4GeneralCollation()
|
||||||
|
{
|
||||||
|
$charset = 'utf8mb4';
|
||||||
|
$collation = 'utf8mb4_general_ci';
|
||||||
|
|
||||||
|
$config = DB::getConfig();
|
||||||
|
$config['charset'] = $charset;
|
||||||
|
$config['driver'] = 'mysql';
|
||||||
|
$config['database'] = 'information_schema';
|
||||||
|
Config::inst()->set(MySQLDatabase::class, 'connection_collation', $collation);
|
||||||
|
|
||||||
|
if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
|
||||||
|
return $this->markTestSkipped('The test only relevant for MySQL');
|
||||||
|
}
|
||||||
|
|
||||||
|
$connector = new PDOConnector();
|
||||||
|
$connector->connect($config);
|
||||||
|
$connection = $connector->getPDOConnection();
|
||||||
|
|
||||||
|
$result = $connection->query(
|
||||||
|
"select `a`.`value` from (select 'rst' `value` union select 'rßt' `value`) `a` order by `value`"
|
||||||
|
)->fetchAll();
|
||||||
|
|
||||||
|
$this->assertCount(1, $result, '`utf8mb4_general_ci` handles both values as equal to "rst"');
|
||||||
|
$this->assertEquals('rst', $result[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUtf8mb4UnicodeCollation()
|
||||||
|
{
|
||||||
|
$charset = 'utf8mb4';
|
||||||
|
$collation = 'utf8mb4_unicode_ci';
|
||||||
|
|
||||||
|
$config = DB::getConfig();
|
||||||
|
$config['charset'] = $charset;
|
||||||
|
$config['driver'] = 'mysql';
|
||||||
|
$config['database'] = 'information_schema';
|
||||||
|
Config::inst()->set(MySQLDatabase::class, 'connection_collation', $collation);
|
||||||
|
|
||||||
|
if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
|
||||||
|
return $this->markTestSkipped('The test only relevant for MySQL');
|
||||||
|
}
|
||||||
|
|
||||||
|
$connector = new PDOConnector();
|
||||||
|
$connector->connect($config);
|
||||||
|
$connection = $connector->getPDOConnection();
|
||||||
|
|
||||||
|
$result = $connection->query(
|
||||||
|
"select `a`.`value` from (select 'rst' `value` union select 'rßt' `value`) `a` order by `value`"
|
||||||
|
)->fetchAll();
|
||||||
|
|
||||||
|
$this->assertCount(2, $result, '`utf8mb4_unicode_ci` must recognise "rst" and "rßt" as different values');
|
||||||
|
$this->assertEquals('rßt', $result[0][0]);
|
||||||
|
$this->assertEquals('rst', $result[1][0]);
|
||||||
|
}
|
||||||
|
}
|
15
tests/php/ORM/MySQLPDOConnectorTest/PDOConnector.php
Normal file
15
tests/php/ORM/MySQLPDOConnectorTest/PDOConnector.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\MySQLPDOConnectorTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\ORM\Connect\PDOConnector as OriginalPDOConnector;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
class PDOConnector extends OriginalPDOConnector implements TestOnly
|
||||||
|
{
|
||||||
|
public function getPDOConnection(): PDO
|
||||||
|
{
|
||||||
|
return $this->pdoConnection;
|
||||||
|
}
|
||||||
|
}
|
149
tests/php/ORM/MySQLiConnectorTest.php
Normal file
149
tests/php/ORM/MySQLiConnectorTest.php
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\SapphireTest;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\ORM\Tests\MySQLiConnectorTest\MySQLiConnector;
|
||||||
|
use SilverStripe\ORM\DB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @requires extension mysqli
|
||||||
|
*/
|
||||||
|
class MySQLiConnectorTest extends SapphireTest implements TestOnly
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @dataProvider charsetProvider
|
||||||
|
*/
|
||||||
|
public function testConnectionCharsetControl($charset, $defaultCollation)
|
||||||
|
{
|
||||||
|
$config = DB::getConfig();
|
||||||
|
$config['charset'] = $charset;
|
||||||
|
$config['database'] = 'information_schema';
|
||||||
|
|
||||||
|
if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
|
||||||
|
return $this->markTestSkipped('The test only relevant for MySQL');
|
||||||
|
}
|
||||||
|
|
||||||
|
$connector = new MySQLiConnector();
|
||||||
|
$connector->connect($config);
|
||||||
|
$connection = $connector->getMysqliConnection();
|
||||||
|
|
||||||
|
$cset = $connection->get_charset();
|
||||||
|
|
||||||
|
$this->assertEquals($charset, $cset->charset);
|
||||||
|
$this->assertEquals($defaultCollation, $cset->collation);
|
||||||
|
|
||||||
|
unset($cset, $connection, $connector, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testConnectionCharsetControl
|
||||||
|
* @dataProvider charsetProvider
|
||||||
|
*/
|
||||||
|
public function testConnectionCollationControl($charset, $defaultCollation, $customCollation)
|
||||||
|
{
|
||||||
|
$config = DB::getConfig();
|
||||||
|
$config['charset'] = $charset;
|
||||||
|
$config['collation'] = $customCollation;
|
||||||
|
$config['database'] = 'information_schema';
|
||||||
|
|
||||||
|
if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
|
||||||
|
return $this->markTestSkipped('The test only relevant for MySQL');
|
||||||
|
}
|
||||||
|
|
||||||
|
$connector = new MySQLiConnector();
|
||||||
|
$connector->connect($config);
|
||||||
|
$connection = $connector->getMysqliConnection();
|
||||||
|
|
||||||
|
$cset = $connection->get_charset();
|
||||||
|
|
||||||
|
$this->assertEquals($charset, $cset->charset);
|
||||||
|
|
||||||
|
/* Warning! This is a MySQLi limitation.
|
||||||
|
* If it changes in the future versions, this test may break.
|
||||||
|
* We are still testing for it as a limitation and a
|
||||||
|
* reminder that it exists.
|
||||||
|
*
|
||||||
|
* To make sure that we actually have correct collation see
|
||||||
|
* - testUtf8mb4GeneralCollation
|
||||||
|
* - testUtf8mb4UnicodeCollation
|
||||||
|
*/
|
||||||
|
$this->assertEquals(
|
||||||
|
$defaultCollation,
|
||||||
|
$cset->collation,
|
||||||
|
'This is an issue with mysqli. It always returns "default" collation, even if another is active'
|
||||||
|
);
|
||||||
|
|
||||||
|
$cset = $connection->query('show variables like "character_set_connection"')->fetch_array()[1];
|
||||||
|
$collation = $connection->query('show variables like "collation_connection"')->fetch_array()[1];
|
||||||
|
|
||||||
|
$this->assertEquals($charset, $cset);
|
||||||
|
$this->assertEquals($customCollation, $collation);
|
||||||
|
|
||||||
|
$connection->close();
|
||||||
|
unset($cset, $connection, $connector, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function charsetProvider()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['ascii', 'ascii_general_ci', 'ascii_bin'],
|
||||||
|
['utf8', 'utf8_general_ci', 'utf8_unicode_520_ci'],
|
||||||
|
['utf8mb4', 'utf8mb4_general_ci', 'utf8mb4_unicode_520_ci']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUtf8mb4GeneralCollation()
|
||||||
|
{
|
||||||
|
$charset = 'utf8mb4';
|
||||||
|
$collation = 'utf8mb4_general_ci';
|
||||||
|
|
||||||
|
$config = DB::getConfig();
|
||||||
|
$config['charset'] = $charset;
|
||||||
|
$config['collation'] = $collation;
|
||||||
|
$config['database'] = 'information_schema';
|
||||||
|
|
||||||
|
if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
|
||||||
|
return $this->markTestSkipped('The test only relevant for MySQL');
|
||||||
|
}
|
||||||
|
|
||||||
|
$connector = new MySQLiConnector();
|
||||||
|
$connector->connect($config, true);
|
||||||
|
$connection = $connector->getMysqliConnection();
|
||||||
|
|
||||||
|
$result = $connection->query(
|
||||||
|
"select `a`.`value` from (select 'rst' `value` union select 'rßt' `value`) `a` order by `value`"
|
||||||
|
)->fetch_all();
|
||||||
|
|
||||||
|
$this->assertCount(1, $result, '`utf8mb4_general_ci` handles both values as equal to "rst"');
|
||||||
|
$this->assertEquals('rst', $result[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUtf8mb4UnicodeCollation()
|
||||||
|
{
|
||||||
|
$charset = 'utf8mb4';
|
||||||
|
$collation = 'utf8mb4_unicode_ci';
|
||||||
|
|
||||||
|
$config = DB::getConfig();
|
||||||
|
$config['charset'] = $charset;
|
||||||
|
$config['collation'] = $collation;
|
||||||
|
$config['database'] = 'information_schema';
|
||||||
|
|
||||||
|
if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
|
||||||
|
return $this->markTestSkipped('The test only relevant for MySQL');
|
||||||
|
}
|
||||||
|
|
||||||
|
$connector = new MySQLiConnector();
|
||||||
|
$connector->connect($config, true);
|
||||||
|
$connection = $connector->getMysqliConnection();
|
||||||
|
|
||||||
|
$result = $connection->query(
|
||||||
|
"select `a`.`value` from (select 'rst' `value` union select 'rßt' `value`) `a` order by `value`"
|
||||||
|
)->fetch_all();
|
||||||
|
|
||||||
|
$this->assertCount(2, $result, '`utf8mb4_unicode_ci` must recognise "rst" and "rßt" as different values');
|
||||||
|
$this->assertEquals('rßt', $result[0][0]);
|
||||||
|
$this->assertEquals('rst', $result[1][0]);
|
||||||
|
}
|
||||||
|
}
|
15
tests/php/ORM/MySQLiConnectorTest/MySQLiConnector.php
Normal file
15
tests/php/ORM/MySQLiConnectorTest/MySQLiConnector.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\MySQLiConnectorTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\ORM\Connect\MySQLiConnector as OriginalMySQLiConnector;
|
||||||
|
use mysqli;
|
||||||
|
|
||||||
|
class MySQLiConnector extends OriginalMySQLiConnector implements TestOnly
|
||||||
|
{
|
||||||
|
public function getMysqliConnection(): mysqli
|
||||||
|
{
|
||||||
|
return $this->dbConn;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user