2 use MediaWiki\MediaWikiServices
;
8 class SearchEnginePrefixTest
extends MediaWikiLangTestCase
{
9 private $originalHandlers;
16 public function addDBDataOnce() {
17 if ( !$this->isWikitextNS( NS_MAIN
) ) {
18 // tests are skipped if NS_MAIN is not wikitext
22 $this->insertPage( 'Sandbox' );
23 $this->insertPage( 'Bar' );
24 $this->insertPage( 'Example' );
25 $this->insertPage( 'Example Bar' );
26 $this->insertPage( 'Example Foo' );
27 $this->insertPage( 'Example Foo/Bar' );
28 $this->insertPage( 'Example/Baz' );
29 $this->insertPage( 'Redirect test', '#REDIRECT [[Redirect Test]]' );
30 $this->insertPage( 'Redirect Test' );
31 $this->insertPage( 'Redirect Test Worse Result' );
32 $this->insertPage( 'Redirect test2', '#REDIRECT [[Redirect Test2]]' );
33 $this->insertPage( 'Redirect TEST2', '#REDIRECT [[Redirect Test2]]' );
34 $this->insertPage( 'Redirect Test2' );
35 $this->insertPage( 'Redirect Test2 Worse Result' );
37 $this->insertPage( 'Talk:Sandbox' );
38 $this->insertPage( 'Talk:Example' );
40 $this->insertPage( 'User:Example' );
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' => [],
56 $this->search
= MediaWikiServices
::getInstance()->newSearchEngine();
57 $this->search
->setNamespaces( [] );
59 $this->originalHandlers
= TestingAccessWrapper
::newFromClass( 'Hooks' )->handlers
;
60 TestingAccessWrapper
::newFromClass( 'Hooks' )->handlers
= [];
62 SpecialPageFactory
::resetList();
65 public function tearDown() {
68 TestingAccessWrapper
::newFromClass( 'Hooks' )->handlers
= $this->originalHandlers
;
70 SpecialPageFactory
::resetList();
73 protected function searchProvision( array $results = null ) {
74 if ( $results === null ) {
75 $this->setMwGlobals( 'wgHooks', [] );
77 $this->setMwGlobals( 'wgHooks', [
78 'PrefixSearchBackend' => [
79 function ( $namespaces, $search, $limit, &$srchres ) use ( $results ) {
88 public static function provideSearch() {
96 'Main namespace with title prefix',
103 // Third result when testing offset
109 'Talk namespace prefix',
117 'User namespace prefix',
124 'Special namespace prefix',
125 'query' => 'Special:',
127 'Special:ActiveUsers',
128 'Special:AllMessages',
129 'Special:AllMyUploads',
131 // Third result when testing offset
137 'Special namespace with prefix',
138 'query' => 'Special:Un',
141 'Special:UncategorizedCategories',
142 'Special:UncategorizedFiles',
144 // Third result when testing offset
146 'Special:UncategorizedPages',
151 'query' => 'Special:EditWatchlist',
153 'Special:EditWatchlist',
157 'Special page subpages',
158 'query' => 'Special:EditWatchlist/',
160 'Special:EditWatchlist/clear',
161 'Special:EditWatchlist/raw',
165 'Special page subpages with prefix',
166 'query' => 'Special:EditWatchlist/cl',
168 'Special:EditWatchlist/clear',
175 * @dataProvider provideSearch
176 * @covers SearchEngine::defaultPrefixSearch
178 public function testSearch( array $case ) {
179 $this->search
->setLimitOffset( 3 );
180 $results = $this->search
->defaultPrefixSearch( $case['query'] );
181 $results = array_map( function( Title
$t ) {
182 return $t->getPrefixedText();
192 * @dataProvider provideSearch
193 * @covers SearchEngine::defaultPrefixSearch
195 public function testSearchWithOffset( array $case ) {
196 $this->search
->setLimitOffset( 3, 1 );
197 $results = $this->search
->defaultPrefixSearch( $case['query'] );
198 $results = array_map( function( Title
$t ) {
199 return $t->getPrefixedText();
202 // We don't expect the first result when offsetting
203 array_shift( $case['results'] );
204 // And sometimes we expect a different last result
205 $expected = isset( $case['offsetresult'] ) ?
206 array_merge( $case['results'], $case['offsetresult'] ) :
216 public static function provideSearchBackend() {
233 'Exact match not on top (T72958)',
247 'Exact match missing (T72958)',
261 'Exact match missing and not existing',
275 "Exact match shouldn't override already found match if " .
276 "exact is redirect and found isn't",
278 // Target of the exact match is low in the list
279 'Redirect Test Worse Result',
282 'query' => 'redirect test',
284 // Redirect target is pulled up and exact match isn't added
286 'Redirect Test Worse Result',
290 "Exact match shouldn't override already found match if " .
291 "both exact match and found match are redirect",
293 // Another redirect to the same target as the exact match
294 // is low in the list
295 'Redirect Test2 Worse Result',
298 'query' => 'redirect TEST2',
300 // Found redirect is pulled to the top and exact match isn't
303 'Redirect Test2 Worse Result',
307 "Exact match should override any already found matches that " .
308 "are redirects to it",
310 // Another redirect to the same target as the exact match
311 // is low in the list
312 'Redirect Test Worse Result',
315 'query' => 'Redirect Test',
317 // Found redirect is pulled to the top and exact match isn't
320 'Redirect Test Worse Result',
328 * @dataProvider provideSearchBackend
329 * @covers PrefixSearch::searchBackend
331 public function testSearchBackend( array $case ) {
332 $search = $stub = $this->getMockBuilder( 'SearchEngine' )
333 ->setMethods( [ 'completionSearchBackend' ] )->getMock();
335 $return = SearchSuggestionSet
::fromStrings( $case['provision'] );
337 $search->expects( $this->any() )
338 ->method( 'completionSearchBackend' )
339 ->will( $this->returnValue( $return ) );
341 $search->setLimitOffset( 3 );
342 $results = $search->completionSearch( $case['query'] );
344 $results = $results->map( function( SearchSuggestion
$s ) {
345 return $s->getText();