7 class PrefixSearchTest
extends MediaWikiLangTestCase
{
8 const NS_NONCAP
= 12346;
10 private $originalHandlers;
12 public function addDBDataOnce() {
13 if ( !$this->isWikitextNS( NS_MAIN
) ) {
14 // tests are skipped if NS_MAIN is not wikitext
18 $this->insertPage( 'Sandbox' );
19 $this->insertPage( 'Bar' );
20 $this->insertPage( 'Example' );
21 $this->insertPage( 'Example Bar' );
22 $this->insertPage( 'Example Foo' );
23 $this->insertPage( 'Example Foo/Bar' );
24 $this->insertPage( 'Example/Baz' );
25 $this->insertPage( 'Redirect test', '#REDIRECT [[Redirect Test]]' );
26 $this->insertPage( 'Redirect Test' );
27 $this->insertPage( 'Redirect Test Worse Result' );
28 $this->insertPage( 'Redirect test2', '#REDIRECT [[Redirect Test2]]' );
29 $this->insertPage( 'Redirect TEST2', '#REDIRECT [[Redirect Test2]]' );
30 $this->insertPage( 'Redirect Test2' );
31 $this->insertPage( 'Redirect Test2 Worse Result' );
33 $this->insertPage( 'Talk:Sandbox' );
34 $this->insertPage( 'Talk:Example' );
36 $this->insertPage( 'User:Example' );
38 $this->insertPage( Title
::makeTitle( self
::NS_NONCAP
, 'Bar' ) );
39 $this->insertPage( Title
::makeTitle( self
::NS_NONCAP
, 'Upper' ) );
40 $this->insertPage( Title
::makeTitle( self
::NS_NONCAP
, 'sandbox' ) );
43 protected function setUp() {
46 if ( !$this->isWikitextNS( NS_MAIN
) ) {
47 $this->markTestSkipped( 'Main namespace does not support wikitext.' );
50 // Avoid special pages from extensions interferring with the tests
51 $this->setMwGlobals( [
52 'wgSpecialPages' => [],
54 'wgExtraNamespaces' => [ self
::NS_NONCAP
=> 'NonCap' ],
55 'wgCapitalLinkOverrides' => [ self
::NS_NONCAP
=> false ],
58 $this->originalHandlers
= TestingAccessWrapper
::newFromClass( 'Hooks' )->handlers
;
59 TestingAccessWrapper
::newFromClass( 'Hooks' )->handlers
= [];
61 // Clear caches so that our new namespace appears
62 MWNamespace
::getCanonicalNamespaces( true );
63 Language
::factory( 'en' )->resetNamespaces();
65 SpecialPageFactory
::resetList();
68 public function tearDown() {
71 TestingAccessWrapper
::newFromClass( 'Hooks' )->handlers
= $this->originalHandlers
;
73 SpecialPageFactory
::resetList();
76 protected function searchProvision( array $results = null ) {
77 if ( $results === null ) {
78 $this->setMwGlobals( 'wgHooks', [] );
80 $this->setMwGlobals( 'wgHooks', [
81 'PrefixSearchBackend' => [
82 function ( $namespaces, $search, $limit, &$srchres ) use ( $results ) {
91 public static function provideSearch() {
99 'Main namespace with title prefix',
106 // Third result when testing offset
112 'Talk namespace prefix',
120 'User namespace prefix',
127 'Special namespace prefix',
128 'query' => 'Special:',
130 'Special:ActiveUsers',
131 'Special:AllMessages',
132 'Special:AllMyUploads',
134 // Third result when testing offset
140 'Special namespace with prefix',
141 'query' => 'Special:Un',
144 'Special:UncategorizedCategories',
145 'Special:UncategorizedFiles',
147 // Third result when testing offset
149 'Special:UncategorizedPages',
154 'query' => 'Special:EditWatchlist',
156 'Special:EditWatchlist',
160 'Special page subpages',
161 'query' => 'Special:EditWatchlist/',
163 'Special:EditWatchlist/clear',
164 'Special:EditWatchlist/raw',
168 'Special page subpages with prefix',
169 'query' => 'Special:EditWatchlist/cl',
171 'Special:EditWatchlist/clear',
175 'Namespace with case sensitive first letter',
176 'query' => 'NonCap:upper',
180 'Multinamespace search',
186 'namespaces' => [ NS_MAIN
, self
::NS_NONCAP
],
189 'Multinamespace search with lowercase first letter',
195 'namespaces' => [ NS_MAIN
, self
::NS_NONCAP
],
201 * @dataProvider provideSearch
202 * @covers PrefixSearch::search
203 * @covers PrefixSearch::searchBackend
205 public function testSearch( array $case ) {
206 $this->searchProvision( null );
208 $namespaces = isset( $case['namespaces'] ) ?
$case['namespaces'] : [];
210 $searcher = new StringPrefixSearch
;
211 $results = $searcher->search( $case['query'], 3, $namespaces );
220 * @dataProvider provideSearch
221 * @covers PrefixSearch::search
222 * @covers PrefixSearch::searchBackend
224 public function testSearchWithOffset( array $case ) {
225 $this->searchProvision( null );
227 $namespaces = isset( $case['namespaces'] ) ?
$case['namespaces'] : [];
229 $searcher = new StringPrefixSearch
;
230 $results = $searcher->search( $case['query'], 3, $namespaces, 1 );
232 // We don't expect the first result when offsetting
233 array_shift( $case['results'] );
234 // And sometimes we expect a different last result
235 $expected = isset( $case['offsetresult'] ) ?
236 array_merge( $case['results'], $case['offsetresult'] ) :
246 public static function provideSearchBackend() {
263 'Exact match not on top (T72958)',
277 'Exact match missing (T72958)',
291 'Exact match missing and not existing',
305 "Exact match shouldn't override already found match if " .
306 "exact is redirect and found isn't",
308 // Target of the exact match is low in the list
309 'Redirect Test Worse Result',
312 'query' => 'redirect test',
314 // Redirect target is pulled up and exact match isn't added
316 'Redirect Test Worse Result',
320 "Exact match shouldn't override already found match if " .
321 "both exact match and found match are redirect",
323 // Another redirect to the same target as the exact match
324 // is low in the list
325 'Redirect Test2 Worse Result',
328 'query' => 'redirect TEST2',
330 // Found redirect is pulled to the top and exact match isn't
333 'Redirect Test2 Worse Result',
337 "Exact match should override any already found matches that " .
338 "are redirects to it",
340 // Another redirect to the same target as the exact match
341 // is low in the list
342 'Redirect Test Worse Result',
345 'query' => 'Redirect Test',
347 // Found redirect is pulled to the top and exact match isn't
350 'Redirect Test Worse Result',
357 * @dataProvider provideSearchBackend
358 * @covers PrefixSearch::searchBackend
360 public function testSearchBackend( array $case ) {
361 $this->searchProvision( $case['provision'] );
362 $searcher = new StringPrefixSearch
;
363 $results = $searcher->search( $case['query'], 3 );