Passed
Push — fix-9163 ( 4cfde3...07a516 )
by Ingo
17:14
created

testConnectionCharsetControl()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 12
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 20
rs 9.8666
1
<?php
2
3
namespace SilverStripe\ORM\Tests;
4
5
use SilverStripe\Dev\SapphireTest;
6
use SilverStripe\Dev\TestOnly;
7
use SilverStripe\ORM\Tests\MySQLiConnectorTest\MySQLiConnector;
8
use SilverStripe\ORM\DB;
9
10
/**
11
 * @requires extension mysqli
12
 */
13
class MySQLiConnectorTest extends SapphireTest implements TestOnly
14
{
15
    /**
16
     * @dataProvider charsetProvider
17
     */
18
    public function testConnectionCharsetControl($charset, $defaultCollation)
19
    {
20
        $config = DB::getConfig();
21
        $config['charset'] = $charset;
22
        $config['database'] = 'information_schema';
23
24
        if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
25
            return $this->markTestSkipped('The test only relevant for MySQL');
26
        }
27
28
        $connector = new MySQLiConnector();
29
        $connector->connect($config);
30
        $connection = $connector->getMysqliConnection();
31
32
        $cset = $connection->get_charset();
33
34
        $this->assertEquals($charset, $cset->charset);
35
        $this->assertEquals($defaultCollation, $cset->collation);
36
37
        unset($cset, $connection, $connector, $config);
38
    }
39
40
    /**
41
     * @dataProvider charsetProvider
42
     */
43
    public function testConnectionCollationControl($charset, $defaultCollation, $customCollation)
44
    {
45
        $config = DB::getConfig();
46
        $config['charset'] = $charset;
47
        $config['collation'] = $customCollation;
48
        $config['database'] = 'information_schema';
49
50
        if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
51
            return $this->markTestSkipped('The test only relevant for MySQL');
52
        }
53
54
        $connector = new MySQLiConnector();
55
        $connector->connect($config);
56
        $connection = $connector->getMysqliConnection();
57
58
        $cset = $connection->get_charset();
59
60
        $this->assertEquals($charset, $cset->charset);
61
62
        /* Warning! This is a MySQLi limitation.
63
         * If it changes in the future versions, this test may break.
64
         * We are still testing for it as a limitation and a
65
         * reminder that it exists.
66
         *
67
         * To make sure that we actually have correct collation see
68
         *  - testUtf8mb4GeneralCollation
69
         *  - testUtf8mb4UnicodeCollation
70
         */
71
        $this->assertEquals(
72
            $defaultCollation,
73
            $cset->collation,
74
            'This is an issue with mysqli. It always returns "default" collation, even if another is active'
75
        );
76
77
        $cset = $connection->query('show variables like "character_set_connection"')->fetch_array()[1];
78
        $collation = $connection->query('show variables like "collation_connection"')->fetch_array()[1];
79
80
        $this->assertEquals($charset, $cset);
81
        $this->assertEquals($customCollation, $collation);
82
83
        $connection->close();
84
        unset($cset, $connection, $connector, $config);
85
    }
86
87
    public function charsetProvider()
88
    {
89
        return [
90
            ['ascii', 'ascii_general_ci', 'ascii_bin'],
91
            ['utf8', 'utf8_general_ci', 'utf8_unicode_520_ci'],
92
            ['utf8mb4', 'utf8mb4_general_ci', 'utf8mb4_unicode_520_ci']
93
        ];
94
    }
95
96
    public function testUtf8mb4GeneralCollation()
97
    {
98
        $charset = 'utf8mb4';
99
        $collation = 'utf8mb4_general_ci';
100
101
        $config = DB::getConfig();
102
        $config['charset'] = $charset;
103
        $config['collation'] = $collation;
104
        $config['database'] = 'information_schema';
105
106
        if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
107
            return $this->markTestSkipped('The test only relevant for MySQL');
108
        }
109
110
        $connector = new MySQLiConnector();
111
        $connector->connect($config, true);
112
        $connection = $connector->getMysqliConnection();
113
114
        $result = $connection->query(
115
            "select `a`.`value` from (select 'rst' `value` union select 'rßt' `value`) `a` order by `value`"
116
        )->fetch_all();
117
118
        $this->assertCount(1, $result, '`utf8mb4_general_ci` handles both values as equal to "rst"');
119
        $this->assertEquals('rst', $result[0][0]);
120
    }
121
122
    public function testUtf8mb4UnicodeCollation()
123
    {
124
        $charset = 'utf8mb4';
125
        $collation = 'utf8mb4_unicode_ci';
126
127
        $config = DB::getConfig();
128
        $config['charset'] = $charset;
129
        $config['collation'] = $collation;
130
        $config['database'] = 'information_schema';
131
132
        if (strtolower(substr($config['type'], 0, 5)) !== 'mysql') {
133
            return $this->markTestSkipped('The test only relevant for MySQL');
134
        }
135
136
        $connector = new MySQLiConnector();
137
        $connector->connect($config, true);
138
        $connection = $connector->getMysqliConnection();
139
140
        $result = $connection->query(
141
            "select `a`.`value` from (select 'rst' `value` union select 'rßt' `value`) `a` order by `value`"
142
        )->fetch_all();
143
144
        $this->assertCount(2, $result, '`utf8mb4_unicode_ci` must recognise "rst" and "rßt" as different values');
145
        $this->assertEquals('rßt', $result[0][0]);
146
        $this->assertEquals('rst', $result[1][0]);
147
    }
148
}
149