Merge "Followup a88df43d: make $wgDebugDumpSql log commented queries again"
[lhc/web/wiklou.git] / tests / phpunit / includes / db / DatabaseMysqlBaseTest.php
1 <?php
2 /**
3 * Holds tests for DatabaseMysqlBase MediaWiki class.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @author Antoine Musso
22 * @author Bryan Davis
23 * @copyright © 2013 Antoine Musso
24 * @copyright © 2013 Bryan Davis
25 * @copyright © 2013 Wikimedia Foundation Inc.
26 */
27
28 /**
29 * Fake class around abstract class so we can call concrete methods.
30 */
31 class FakeDatabaseMysqlBase extends DatabaseMysqlBase {
32 // From DatabaseBase
33 function __construct() {
34 }
35
36 protected function closeConnection() {
37 }
38
39 protected function doQuery( $sql ) {
40 }
41
42 // From DatabaseMysql
43 protected function mysqlConnect( $realServer ) {
44 }
45
46 protected function mysqlSetCharset( $charset ) {
47 }
48
49 protected function mysqlFreeResult( $res ) {
50 }
51
52 protected function mysqlFetchObject( $res ) {
53 }
54
55 protected function mysqlFetchArray( $res ) {
56 }
57
58 protected function mysqlNumRows( $res ) {
59 }
60
61 protected function mysqlNumFields( $res ) {
62 }
63
64 protected function mysqlFieldName( $res, $n ) {
65 }
66
67 protected function mysqlFieldType( $res, $n ) {
68 }
69
70 protected function mysqlDataSeek( $res, $row ) {
71 }
72
73 protected function mysqlError( $conn = null ) {
74 }
75
76 protected function mysqlFetchField( $res, $n ) {
77 }
78
79 protected function mysqlPing() {
80 }
81
82 protected function mysqlRealEscapeString( $s ) {
83
84 }
85
86 // From interface DatabaseType
87 function insertId() {
88 }
89
90 function lastErrno() {
91 }
92
93 function affectedRows() {
94 }
95
96 function getServerVersion() {
97 }
98 }
99
100 class DatabaseMysqlBaseTest extends MediaWikiTestCase {
101 /**
102 * @dataProvider provideDiapers
103 * @covers DatabaseMysqlBase::addIdentifierQuotes
104 */
105 public function testAddIdentifierQuotes( $expected, $in ) {
106 $db = new FakeDatabaseMysqlBase();
107 $quoted = $db->addIdentifierQuotes( $in );
108 $this->assertEquals( $expected, $quoted );
109 }
110
111 /**
112 * Feeds testAddIdentifierQuotes
113 *
114 * Named per bug 20281 convention.
115 */
116 function provideDiapers() {
117 return array(
118 // Format: expected, input
119 array( '``', '' ),
120
121 // Yeah I really hate loosely typed PHP idiocies nowadays
122 array( '``', null ),
123
124 // Dear codereviewer, guess what addIdentifierQuotes()
125 // will return with thoses:
126 array( '``', false ),
127 array( '`1`', true ),
128
129 // We never know what could happen
130 array( '`0`', 0 ),
131 array( '`1`', 1 ),
132
133 // Whatchout! Should probably use something more meaningful
134 array( "`'`", "'" ), # single quote
135 array( '`"`', '"' ), # double quote
136 array( '````', '`' ), # backtick
137 array( '`’`', '’' ), # apostrophe (look at your encyclopedia)
138
139 // sneaky NUL bytes are lurking everywhere
140 array( '``', "\0" ),
141 array( '`xyzzy`', "\0x\0y\0z\0z\0y\0" ),
142
143 // unicode chars
144 array(
145 self::createUnicodeString( '`\u0001a\uFFFFb`' ),
146 self::createUnicodeString( '\u0001a\uFFFFb' )
147 ),
148 array(
149 self::createUnicodeString( '`\u0001\uFFFF`' ),
150 self::createUnicodeString( '\u0001\u0000\uFFFF\u0000' )
151 ),
152 array( '`☃`', '☃' ),
153 array( '`メインページ`', 'メインページ' ),
154 array( '`Басты_бет`', 'Басты_бет' ),
155
156 // Real world:
157 array( '`Alix`', 'Alix' ), # while( ! $recovered ) { sleep(); }
158 array( '`Backtick: ```', 'Backtick: `' ),
159 array( '`This is a test`', 'This is a test' ),
160 );
161 }
162
163 private static function createUnicodeString( $str ) {
164 return json_decode( '"' . $str . '"' );
165 }
166
167 function getMockForViews() {
168 $db = $this->getMockBuilder( 'DatabaseMysql' )
169 ->disableOriginalConstructor()
170 ->setMethods( array( 'fetchRow', 'query' ) )
171 ->getMock();
172
173 $db->expects( $this->any() )
174 ->method( 'query' )
175 ->with( $this->anything() )
176 ->will(
177 $this->returnValue( null )
178 );
179
180 $db->expects( $this->any() )
181 ->method( 'fetchRow' )
182 ->with( $this->anything() )
183 ->will( $this->onConsecutiveCalls(
184 array( 'Tables_in_' => 'view1' ),
185 array( 'Tables_in_' => 'view2' ),
186 array( 'Tables_in_' => 'myview' ),
187 false # no more rows
188 ) );
189 return $db;
190 }
191 /**
192 * @covers DatabaseMysqlBase::listViews
193 */
194 function testListviews() {
195 $db = $this->getMockForViews();
196
197 // The first call populate an internal cache of views
198 $this->assertEquals( array( 'view1', 'view2', 'myview' ),
199 $db->listViews() );
200 $this->assertEquals( array( 'view1', 'view2', 'myview' ),
201 $db->listViews() );
202
203 // Prefix filtering
204 $this->assertEquals( array( 'view1', 'view2' ),
205 $db->listViews( 'view' ) );
206 $this->assertEquals( array( 'myview' ),
207 $db->listViews( 'my' ) );
208 $this->assertEquals( array(),
209 $db->listViews( 'UNUSED_PREFIX' ) );
210 $this->assertEquals( array( 'view1', 'view2', 'myview' ),
211 $db->listViews( '' ) );
212 }
213
214 /**
215 * @covers DatabaseMysqlBase::isView
216 * @dataProvider provideViewExistanceChecks
217 */
218 function testIsView( $isView, $viewName ) {
219 $db = $this->getMockForViews();
220
221 switch ( $isView ) {
222 case true:
223 $this->assertTrue( $db->isView( $viewName ),
224 "$viewName should be considered a view" );
225 break;
226
227 case false:
228 $this->assertFalse( $db->isView( $viewName ),
229 "$viewName has not been defined as a view" );
230 break;
231 }
232
233 }
234
235 function provideViewExistanceChecks() {
236 return array(
237 // format: whether it is a view, view name
238 array( true, 'view1' ),
239 array( true, 'view2' ),
240 array( true, 'myview' ),
241
242 array( false, 'user' ),
243
244 array( false, 'view10' ),
245 array( false, 'my' ),
246 array( false, 'OH_MY_GOD' ), # they killed kenny!
247 );
248 }
249
250 function testMasterPos() {
251 $pos1 = new MySQLMasterPos( 'db1034-bin.000976', '843431247' );
252 $pos2 = new MySQLMasterPos( 'db1034-bin.000976', '843431248' );
253
254 $this->assertTrue( $pos1->hasReached( $pos1 ) );
255 $this->assertTrue( $pos2->hasReached( $pos2 ) );
256 $this->assertTrue( $pos2->hasReached( $pos1 ) );
257 $this->assertFalse( $pos1->hasReached( $pos2 ) );
258 }
259 }