5 * Created on Feb 6, 2013
7 * Copyright © 2013 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * http://www.gnu.org/copyleft/gpl.html
26 * These tests validate basic functionality of the api query module
32 class ApiQueryBasicTest
extends ApiTestCase
{
34 * Create a set of pages. These must not change, otherwise the tests might give wrong results.
35 * @see MediaWikiTestCase::addDBData()
37 function addDBData() {
39 if ( Title
::newFromText( 'AQBT-All' )->exists() ) {
43 // Ordering is important, as it will be returned in the same order as stored in the index
44 $this->editPage( 'AQBT-All', '[[Category:AQBT-Cat]] [[AQBT-Links]] {{AQBT-T}}' );
45 $this->editPage( 'AQBT-Categories', '[[Category:AQBT-Cat]]' );
46 $this->editPage( 'AQBT-Links', '[[AQBT-All]] [[AQBT-Categories]] [[AQBT-Templates]]' );
47 $this->editPage( 'AQBT-Templates', '{{AQBT-T}}' );
48 $this->editPage( 'AQBT-T', 'Content', '', NS_TEMPLATE
);
50 // Refresh due to the bug with listing transclusions as links if they don't exist
51 $this->editPage( 'AQBT-All', '[[Category:AQBT-Cat]] [[AQBT-Links]] {{AQBT-T}}' );
52 $this->editPage( 'AQBT-Templates', '{{AQBT-T}}' );
53 } catch ( Exception
$e ) {
54 $this->exceptionFromAddDBData
= $e;
58 private static $links = array(
59 array( 'prop' => 'links', 'titles' => 'AQBT-All' ),
60 array( 'pages' => array(
64 'title' => 'AQBT-All',
66 array( 'ns' => 0, 'title' => 'AQBT-Links' ),
69 private static $templates = array(
70 array( 'prop' => 'templates', 'titles' => 'AQBT-All' ),
71 array( 'pages' => array(
75 'title' => 'AQBT-All',
77 array( 'ns' => 10, 'title' => 'Template:AQBT-T' ),
80 private static $categories = array(
81 array( 'prop' => 'categories', 'titles' => 'AQBT-All' ),
82 array( 'pages' => array(
86 'title' => 'AQBT-All',
87 'categories' => array(
88 array( 'ns' => 14, 'title' => 'Category:AQBT-Cat' ),
91 private static $allpages = array(
92 array( 'list' => 'allpages', 'apprefix' => 'AQBT-' ),
93 array( 'allpages' => array(
94 array( 'pageid' => 1, 'ns' => 0, 'title' => 'AQBT-All' ),
95 array( 'pageid' => 2, 'ns' => 0, 'title' => 'AQBT-Categories' ),
96 array( 'pageid' => 3, 'ns' => 0, 'title' => 'AQBT-Links' ),
97 array( 'pageid' => 4, 'ns' => 0, 'title' => 'AQBT-Templates' ),
100 private static $alllinks = array(
101 array( 'list' => 'alllinks', 'alprefix' => 'AQBT-' ),
102 array( 'alllinks' => array(
103 array( 'ns' => 0, 'title' => 'AQBT-All' ),
104 array( 'ns' => 0, 'title' => 'AQBT-Categories' ),
105 array( 'ns' => 0, 'title' => 'AQBT-Links' ),
106 array( 'ns' => 0, 'title' => 'AQBT-Templates' ),
109 private static $alltransclusions = array(
110 array( 'list' => 'alltransclusions', 'atprefix' => 'AQBT-' ),
111 array( 'alltransclusions' => array(
112 array( 'ns' => 10, 'title' => 'Template:AQBT-T' ),
113 array( 'ns' => 10, 'title' => 'Template:AQBT-T' ),
116 private static $allcategories = array(
117 array( 'list' => 'allcategories', 'acprefix' => 'AQBT-' ),
118 array( 'allcategories' => array(
119 array( '*' => 'AQBT-Cat' ),
122 private static $backlinks = array(
123 array( 'list' => 'backlinks', 'bltitle' => 'AQBT-Links' ),
124 array( 'backlinks' => array(
125 array( 'pageid' => 1, 'ns' => 0, 'title' => 'AQBT-All' ),
128 private static $embeddedin = array(
129 array( 'list' => 'embeddedin', 'eititle' => 'Template:AQBT-T' ),
130 array( 'embeddedin' => array(
131 array( 'pageid' => 1, 'ns' => 0, 'title' => 'AQBT-All' ),
132 array( 'pageid' => 4, 'ns' => 0, 'title' => 'AQBT-Templates' ),
135 private static $categorymembers = array(
136 array( 'list' => 'categorymembers', 'cmtitle' => 'Category:AQBT-Cat' ),
137 array( 'categorymembers' => array(
138 array( 'pageid' => 1, 'ns' => 0, 'title' => 'AQBT-All' ),
139 array( 'pageid' => 2, 'ns' => 0, 'title' => 'AQBT-Categories' ),
142 private static $generatorAllpages = array(
143 array( 'generator' => 'allpages', 'gapprefix' => 'AQBT-' ),
144 array( 'pages' => array(
148 'title' => 'AQBT-All' ),
152 'title' => 'AQBT-Categories' ),
156 'title' => 'AQBT-Links' ),
160 'title' => 'AQBT-Templates' ),
163 private static $generatorLinks = array(
164 array( 'generator' => 'links', 'titles' => 'AQBT-Links' ),
165 array( 'pages' => array(
169 'title' => 'AQBT-All' ),
173 'title' => 'AQBT-Categories' ),
177 'title' => 'AQBT-Templates' ),
180 private static $generatorLinksPropLinks = array(
181 array( 'prop' => 'links' ),
182 array( 'pages' => array(
183 '1' => array( 'links' => array(
184 array( 'ns' => 0, 'title' => 'AQBT-Links' ),
187 private static $generatorLinksPropTemplates = array(
188 array( 'prop' => 'templates' ),
189 array( 'pages' => array(
190 '1' => array( 'templates' => array(
191 array( 'ns' => 10, 'title' => 'Template:AQBT-T' ) ) ),
192 '4' => array( 'templates' => array(
193 array( 'ns' => 10, 'title' => 'Template:AQBT-T' ) ) ),
199 public function testProps() {
200 $this->check( self
::$links );
201 $this->check( self
::$templates );
202 $this->check( self
::$categories );
208 public function testLists() {
209 $this->check( self
::$allpages );
210 $this->check( self
::$alllinks );
211 $this->check( self
::$alltransclusions );
212 // This test is temporarily disabled until a sqlite bug is fixed
213 // $this->check( self::$allcategories );
214 $this->check( self
::$backlinks );
215 $this->check( self
::$embeddedin );
216 $this->check( self
::$categorymembers );
222 public function testAllTogether() {
224 // All props together
225 $this->check( $this->merge(
231 // All lists together
232 $this->check( $this->merge(
235 self
::$alltransclusions,
236 // This test is temporarily disabled until a sqlite bug is fixed
237 // self::$allcategories,
240 self
::$categorymembers
243 // All props+lists together
244 $this->check( $this->merge(
250 self
::$alltransclusions,
251 // This test is temporarily disabled until a sqlite bug is fixed
252 // self::$allcategories,
255 self
::$categorymembers
262 public function testGenerator() {
263 // generator=allpages
264 $this->check( self
::$generatorAllpages );
265 // generator=allpages & list=allpages
266 $this->check( $this->merge(
267 self
::$generatorAllpages,
270 $this->check( self
::$generatorLinks );
271 // generator=links & prop=links
272 $this->check( $this->merge(
273 self
::$generatorLinks,
274 self
::$generatorLinksPropLinks ) );
275 // generator=links & prop=templates
276 $this->check( $this->merge(
277 self
::$generatorLinks,
278 self
::$generatorLinksPropTemplates ) );
279 // generator=links & prop=links|templates
280 $this->check( $this->merge(
281 self
::$generatorLinks,
282 self
::$generatorLinksPropLinks,
283 self
::$generatorLinksPropTemplates ) );
284 // generator=links & prop=links|templates & list=allpages|...
285 $this->check( $this->merge(
286 self
::$generatorLinks,
287 self
::$generatorLinksPropLinks,
288 self
::$generatorLinksPropTemplates,
291 self
::$alltransclusions,
292 // This test is temporarily disabled until a sqlite bug is fixed
293 // self::$allcategories,
296 self
::$categorymembers ) );
300 * Merges all requests (parameter arrays) into one
303 private function merge( /*...*/ ) {
306 foreach ( func_get_args() as $v ) {
307 $request = array_merge_recursive( $request, $v[0] );
308 $this->mergeExpected( $expected, $v[1] );
310 return array( $request, $expected );
314 * Recursively merges the expected values in the $item into the $all
316 private function mergeExpected( &$all, $item ) {
317 foreach ( $item as $k => $v ) {
318 if ( array_key_exists( $k, $all ) ) {
319 if ( is_array( $all[$k] ) ) {
320 $this->mergeExpected( $all[$k], $v );
322 $this->assertEquals( $all[$k], $v );
331 * Checks that the request's result matches the expected results.
332 * @param $values array is a two element array( request, expected_results )
335 private function check( $values ) {
336 $request = $values[0];
337 $expected = $values[1];
338 if ( !array_key_exists( 'action', $request ) ) {
339 $request['action'] = 'query';
341 foreach ( $request as &$val ) {
342 if ( is_array( $val ) ) {
343 $val = implode( '|', array_unique( $val ) );
346 $result = $this->doApiRequest( $request );
347 $result = $result[0];
348 $expected = array( 'query' => $expected );
350 $this->assertQueryResults( $expected, $result );
351 } catch ( Exception
$e ) {
352 print( "\nRequest:\n" );
354 print( "\nExpected:\n" );
355 print_r( $expected );
356 print( "\nResult:\n" );
358 throw $e; // rethrow it
363 * Recursively compare arrays, ignoring mismatches in numeric key and pageids.
364 * @param $expected array expected values
365 * @param $result array returned values
367 private function assertQueryResults( $expected, $result ) {
371 $e = each( $expected );
372 $r = each( $result );
373 // If either of the arrays is shorter, abort. If both are done, success.
374 $this->assertEquals( (bool)$e, (bool)$r );
378 // continue only if keys are identical or both keys are numeric
379 $this->assertTrue( $e['key'] === $r['key'] ||
( is_numeric( $e['key'] ) && is_numeric( $r['key'] ) ) );
380 // don't compare pageids
381 if ( $e['key'] !== 'pageid' ) {
382 // If values are arrays, compare recursively, otherwise compare with ===
383 if ( is_array( $e['value'] ) && is_array( $r['value'] ) ) {
384 $this->assertQueryResults( $e['value'], $r['value'] );
386 $this->assertEquals( $e['value'], $r['value'] );