3 use MediaWiki\MainConfigNames
;
4 use MediaWiki\Title\Title
;
9 * @covers \PrefixSearch
11 class PrefixSearchTest
extends MediaWikiLangTestCase
{
12 private const NS_NONCAP
= 12346;
14 public function addDBDataOnce() {
15 if ( !$this->isWikitextNS( NS_MAIN
) ) {
16 // tests are skipped if NS_MAIN is not wikitext
20 $this->insertPage( 'Sandbox' );
21 $this->insertPage( 'Bar' );
22 $this->insertPage( 'Example' );
23 $this->insertPage( 'Example Bar' );
24 $this->insertPage( 'Example Foo' );
25 $this->insertPage( 'Example Foo/Bar' );
26 $this->insertPage( 'Example/Baz' );
27 $this->insertPage( 'Redirect test', '#REDIRECT [[Redirect Test]]' );
28 $this->insertPage( 'Redirect Test' );
29 $this->insertPage( 'Redirect Test Worse Result' );
30 $this->insertPage( 'Redirect test2', '#REDIRECT [[Redirect Test2]]' );
31 $this->insertPage( 'Redirect TEST2', '#REDIRECT [[Redirect Test2]]' );
32 $this->insertPage( 'Redirect Test2' );
33 $this->insertPage( 'Redirect Test2 Worse Result' );
35 $this->insertPage( 'Talk:Sandbox' );
36 $this->insertPage( 'Talk:Example' );
38 $this->insertPage( 'User:Example' );
40 $this->overrideConfigValues( [
41 MainConfigNames
::ExtraNamespaces
=> [ self
::NS_NONCAP
=> 'NonCap' ],
42 MainConfigNames
::CapitalLinkOverrides
=> [ self
::NS_NONCAP
=> false ],
45 $this->insertPage( Title
::makeTitle( self
::NS_NONCAP
, 'Bar' ) );
46 $this->insertPage( Title
::makeTitle( self
::NS_NONCAP
, 'Upper' ) );
47 $this->insertPage( Title
::makeTitle( self
::NS_NONCAP
, 'sandbox' ) );
50 protected function setUp(): void
{
53 if ( !$this->isWikitextNS( NS_MAIN
) ) {
54 $this->markTestSkipped( 'Main namespace does not support wikitext.' );
57 // Avoid special pages from extensions interfering with the tests
58 $this->overrideConfigValues( [
59 MainConfigNames
::SpecialPages
=> [],
60 MainConfigNames
::Hooks
=> [],
61 MainConfigNames
::ExtraNamespaces
=> [ self
::NS_NONCAP
=> 'NonCap' ],
62 MainConfigNames
::CapitalLinkOverrides
=> [ self
::NS_NONCAP
=> false ],
66 protected function searchProvision( ?
array $results = null ) {
67 if ( $results === null ) {
68 $this->overrideConfigValue( MainConfigNames
::Hooks
, [] );
70 $this->setTemporaryHook(
71 'PrefixSearchBackend',
72 static function ( $namespaces, $search, $limit, &$srchres ) use ( $results ) {
80 public static function provideSearch() {
88 'Main namespace with title prefix',
95 // Third result when testing offset
101 'Talk namespace prefix',
109 'User namespace prefix',
116 'Special namespace prefix',
117 'query' => 'Special:',
119 'Special:ActiveUsers',
120 'Special:AllMessages',
123 // Third result when testing offset
125 'Special:AncientPages',
129 'Special namespace with prefix',
130 'query' => 'Special:Un',
133 'Special:UncategorizedCategories',
134 'Special:UncategorizedFiles',
136 // Third result when testing offset
138 'Special:UncategorizedPages',
143 'query' => 'Special:EditWatchlist',
147 'Special page subpages',
148 'query' => 'Special:EditWatchlist/',
150 'Special:EditWatchlist/clear',
151 'Special:EditWatchlist/raw',
155 'Special page subpages with prefix',
156 'query' => 'Special:EditWatchlist/cl',
158 'Special:EditWatchlist/clear',
162 'Namespace with case sensitive first letter',
163 'query' => 'NonCap:upper',
167 'Multinamespace search',
173 'namespaces' => [ NS_MAIN
, self
::NS_NONCAP
],
176 'Multinamespace search with lowercase first letter',
182 'namespaces' => [ NS_MAIN
, self
::NS_NONCAP
],
188 * @dataProvider provideSearch
189 * @covers \PrefixSearch::search
190 * @covers \PrefixSearch::searchBackend
192 public function testSearch( array $case ) {
193 $this->searchProvision( null );
195 $namespaces = $case['namespaces'] ??
[];
197 $searcher = new StringPrefixSearch
;
198 $results = $searcher->search( $case['query'], 3, $namespaces );
207 * @dataProvider provideSearch
208 * @covers \PrefixSearch::search
209 * @covers \PrefixSearch::searchBackend
211 public function testSearchWithOffset( array $case ) {
212 $this->searchProvision( null );
214 $namespaces = $case['namespaces'] ??
[];
216 $searcher = new StringPrefixSearch
;
217 $results = $searcher->search( $case['query'], 3, $namespaces, 1 );
219 // We don't expect the first result when offsetting
220 array_shift( $case['results'] );
221 // And sometimes we expect a different last result
222 $expected = isset( $case['offsetresult'] ) ?
223 array_merge( $case['results'], $case['offsetresult'] ) :
233 public static function provideSearchBackend() {
250 'Exact match not on top (T72958)',
264 'Exact match missing (T72958)',
278 'Exact match missing and not existing',
292 "Exact match shouldn't override already found match if " .
293 "exact is redirect and found isn't",
295 // Target of the exact match is low in the list
296 'Redirect Test Worse Result',
299 'query' => 'redirect test',
301 // Redirect target is pulled up and exact match isn't added
303 'Redirect Test Worse Result',
307 "Exact match should override already found match if " .
308 "both exact match and found match are redirect",
310 // Another redirect to the same target as the exact match
311 // is low in the list
312 'Redirect Test2 Worse Result',
315 'query' => 'redirect TEST2',
317 // Found redirect is pulled to the top and exact match isn't
320 'Redirect Test2 Worse Result',
324 "Exact match should override any already found matches that " .
325 "are redirects to it",
327 // Another redirect to the same target as the exact match
328 // is low in the list
329 'Redirect Test Worse Result',
332 'query' => 'Redirect Test',
334 // Found redirect is pulled to the top and exact match isn't
337 'Redirect Test Worse Result',
344 * @dataProvider provideSearchBackend
345 * @covers \PrefixSearch::searchBackend
347 public function testSearchBackend( array $case ) {
348 $this->filterDeprecated( '/Use of PrefixSearchBackend hook/' );
349 $this->searchProvision( $case['provision'] );
350 $searcher = new StringPrefixSearch
;
351 $results = $searcher->search( $case['query'], 3 );