Merge "Remove DELETE_SOURCE flag from FileRepo store()/storeBatch()"
[lhc/web/wiklou.git] / tests / phpunit / includes / PrefixSearchTest.php
1 <?php
2 /**
3 * @group Search
4 * @group Database
5 */
6 class PrefixSearchTest extends MediaWikiLangTestCase {
7 private $originalHandlers;
8
9 public function addDBDataOnce() {
10 if ( !$this->isWikitextNS( NS_MAIN ) ) {
11 // tests are skipped if NS_MAIN is not wikitext
12 return;
13 }
14
15 $this->insertPage( 'Sandbox' );
16 $this->insertPage( 'Bar' );
17 $this->insertPage( 'Example' );
18 $this->insertPage( 'Example Bar' );
19 $this->insertPage( 'Example Foo' );
20 $this->insertPage( 'Example Foo/Bar' );
21 $this->insertPage( 'Example/Baz' );
22 $this->insertPage( 'Redirect test', '#REDIRECT [[Redirect Test]]' );
23 $this->insertPage( 'Redirect Test' );
24 $this->insertPage( 'Redirect Test Worse Result' );
25 $this->insertPage( 'Redirect test2', '#REDIRECT [[Redirect Test2]]' );
26 $this->insertPage( 'Redirect TEST2', '#REDIRECT [[Redirect Test2]]' );
27 $this->insertPage( 'Redirect Test2' );
28 $this->insertPage( 'Redirect Test2 Worse Result' );
29
30 $this->insertPage( 'Talk:Sandbox' );
31 $this->insertPage( 'Talk:Example' );
32
33 $this->insertPage( 'User:Example' );
34 }
35
36 protected function setUp() {
37 parent::setUp();
38
39 if ( !$this->isWikitextNS( NS_MAIN ) ) {
40 $this->markTestSkipped( 'Main namespace does not support wikitext.' );
41 }
42
43 // Avoid special pages from extensions interferring with the tests
44 $this->setMwGlobals( [
45 'wgSpecialPages' => [],
46 'wgHooks' => [],
47 ] );
48
49 $this->originalHandlers = TestingAccessWrapper::newFromClass( 'Hooks' )->handlers;
50 TestingAccessWrapper::newFromClass( 'Hooks' )->handlers = [];
51
52 SpecialPageFactory::resetList();
53 }
54
55 public function tearDown() {
56 parent::tearDown();
57
58 TestingAccessWrapper::newFromClass( 'Hooks' )->handlers = $this->originalHandlers;
59
60 SpecialPageFactory::resetList();
61 }
62
63 protected function searchProvision( array $results = null ) {
64 if ( $results === null ) {
65 $this->setMwGlobals( 'wgHooks', [] );
66 } else {
67 $this->setMwGlobals( 'wgHooks', [
68 'PrefixSearchBackend' => [
69 function ( $namespaces, $search, $limit, &$srchres ) use ( $results ) {
70 $srchres = $results;
71 return false;
72 }
73 ],
74 ] );
75 }
76 }
77
78 public static function provideSearch() {
79 return [
80 [ [
81 'Empty string',
82 'query' => '',
83 'results' => [],
84 ] ],
85 [ [
86 'Main namespace with title prefix',
87 'query' => 'Ex',
88 'results' => [
89 'Example',
90 'Example/Baz',
91 'Example Bar',
92 ],
93 // Third result when testing offset
94 'offsetresult' => [
95 'Example Foo',
96 ],
97 ] ],
98 [ [
99 'Talk namespace prefix',
100 'query' => 'Talk:',
101 'results' => [
102 'Talk:Example',
103 'Talk:Sandbox',
104 ],
105 ] ],
106 [ [
107 'User namespace prefix',
108 'query' => 'User:',
109 'results' => [
110 'User:Example',
111 ],
112 ] ],
113 [ [
114 'Special namespace prefix',
115 'query' => 'Special:',
116 'results' => [
117 'Special:ActiveUsers',
118 'Special:AllMessages',
119 'Special:AllMyFiles',
120 ],
121 // Third result when testing offset
122 'offsetresult' => [
123 'Special:AllMyUploads',
124 ],
125 ] ],
126 [ [
127 'Special namespace with prefix',
128 'query' => 'Special:Un',
129 'results' => [
130 'Special:Unblock',
131 'Special:UncategorizedCategories',
132 'Special:UncategorizedFiles',
133 ],
134 // Third result when testing offset
135 'offsetresult' => [
136 'Special:UncategorizedImages',
137 ],
138 ] ],
139 [ [
140 'Special page name',
141 'query' => 'Special:EditWatchlist',
142 'results' => [
143 'Special:EditWatchlist',
144 ],
145 ] ],
146 [ [
147 'Special page subpages',
148 'query' => 'Special:EditWatchlist/',
149 'results' => [
150 'Special:EditWatchlist/clear',
151 'Special:EditWatchlist/raw',
152 ],
153 ] ],
154 [ [
155 'Special page subpages with prefix',
156 'query' => 'Special:EditWatchlist/cl',
157 'results' => [
158 'Special:EditWatchlist/clear',
159 ],
160 ] ],
161 ];
162 }
163
164 /**
165 * @dataProvider provideSearch
166 * @covers PrefixSearch::search
167 * @covers PrefixSearch::searchBackend
168 */
169 public function testSearch( array $case ) {
170 $this->searchProvision( null );
171 $searcher = new StringPrefixSearch;
172 $results = $searcher->search( $case['query'], 3 );
173 $this->assertEquals(
174 $case['results'],
175 $results,
176 $case[0]
177 );
178 }
179
180 /**
181 * @dataProvider provideSearch
182 * @covers PrefixSearch::search
183 * @covers PrefixSearch::searchBackend
184 */
185 public function testSearchWithOffset( array $case ) {
186 $this->searchProvision( null );
187 $searcher = new StringPrefixSearch;
188 $results = $searcher->search( $case['query'], 3, [], 1 );
189
190 // We don't expect the first result when offsetting
191 array_shift( $case['results'] );
192 // And sometimes we expect a different last result
193 $expected = isset( $case['offsetresult'] ) ?
194 array_merge( $case['results'], $case['offsetresult'] ) :
195 $case['results'];
196
197 $this->assertEquals(
198 $expected,
199 $results,
200 $case[0]
201 );
202 }
203
204 public static function provideSearchBackend() {
205 return [
206 [ [
207 'Simple case',
208 'provision' => [
209 'Bar',
210 'Barcelona',
211 'Barbara',
212 ],
213 'query' => 'Bar',
214 'results' => [
215 'Bar',
216 'Barcelona',
217 'Barbara',
218 ],
219 ] ],
220 [ [
221 'Exact match not on top (bug 70958)',
222 'provision' => [
223 'Barcelona',
224 'Bar',
225 'Barbara',
226 ],
227 'query' => 'Bar',
228 'results' => [
229 'Bar',
230 'Barcelona',
231 'Barbara',
232 ],
233 ] ],
234 [ [
235 'Exact match missing (bug 70958)',
236 'provision' => [
237 'Barcelona',
238 'Barbara',
239 'Bart',
240 ],
241 'query' => 'Bar',
242 'results' => [
243 'Bar',
244 'Barcelona',
245 'Barbara',
246 ],
247 ] ],
248 [ [
249 'Exact match missing and not existing',
250 'provision' => [
251 'Exile',
252 'Exist',
253 'External',
254 ],
255 'query' => 'Ex',
256 'results' => [
257 'Exile',
258 'Exist',
259 'External',
260 ],
261 ] ],
262 [ [
263 "Exact match shouldn't override already found match if " .
264 "exact is redirect and found isn't",
265 'provision' => [
266 // Target of the exact match is low in the list
267 'Redirect Test Worse Result',
268 'Redirect Test',
269 ],
270 'query' => 'redirect test',
271 'results' => [
272 // Redirect target is pulled up and exact match isn't added
273 'Redirect Test',
274 'Redirect Test Worse Result',
275 ],
276 ] ],
277 [ [
278 "Exact match shouldn't override already found match if " .
279 "both exact match and found match are redirect",
280 'provision' => [
281 // Another redirect to the same target as the exact match
282 // is low in the list
283 'Redirect Test2 Worse Result',
284 'Redirect test2',
285 ],
286 'query' => 'redirect TEST2',
287 'results' => [
288 // Found redirect is pulled to the top and exact match isn't
289 // added
290 'Redirect test2',
291 'Redirect Test2 Worse Result',
292 ],
293 ] ],
294 [ [
295 "Exact match should override any already found matches that " .
296 "are redirects to it",
297 'provision' => [
298 // Another redirect to the same target as the exact match
299 // is low in the list
300 'Redirect Test Worse Result',
301 'Redirect test',
302 ],
303 'query' => 'Redirect Test',
304 'results' => [
305 // Found redirect is pulled to the top and exact match isn't
306 // added
307 'Redirect Test',
308 'Redirect Test Worse Result',
309 ],
310 ] ],
311 ];
312 }
313
314 /**
315 * @dataProvider provideSearchBackend
316 * @covers PrefixSearch::searchBackend
317 */
318 public function testSearchBackend( array $case ) {
319 $this->searchProvision( $case['provision'] );
320 $searcher = new StringPrefixSearch;
321 $results = $searcher->search( $case['query'], 3 );
322 $this->assertEquals(
323 $case['results'],
324 $results,
325 $case[0]
326 );
327 }
328 }