2010-12-14 16:26:35 +00:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @group Search
|
2011-06-28 22:26:22 +00:00
|
|
|
|
* @group Database
|
2013-10-24 19:35:04 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @covers SearchEngine<extended>
|
|
|
|
|
|
* @note Coverage will only ever show one of on of the Search* classes
|
2010-12-14 16:26:35 +00:00
|
|
|
|
*/
|
2012-11-11 07:13:21 +00:00
|
|
|
|
class SearchEngineTest extends MediaWikiLangTestCase {
|
2014-01-03 01:23:16 +00:00
|
|
|
|
|
2013-10-24 19:35:04 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @var SearchEngine
|
|
|
|
|
|
*/
|
|
|
|
|
|
protected $search;
|
2014-01-03 01:23:16 +00:00
|
|
|
|
|
2011-10-26 03:45:13 +00:00
|
|
|
|
/**
|
2010-12-14 16:26:35 +00:00
|
|
|
|
* Checks for database type & version.
|
|
|
|
|
|
* Will skip current test if DB does not support search.
|
|
|
|
|
|
*/
|
2012-10-08 10:56:20 +00:00
|
|
|
|
protected function setUp() {
|
2011-06-28 22:26:22 +00:00
|
|
|
|
parent::setUp();
|
2012-11-11 07:13:21 +00:00
|
|
|
|
|
2010-12-14 16:26:35 +00:00
|
|
|
|
// Search tests require MySQL or SQLite with FTS
|
2011-06-16 20:57:31 +00:00
|
|
|
|
$dbType = $this->db->getType();
|
2014-01-03 01:23:16 +00:00
|
|
|
|
$dbSupported = ( $dbType === 'mysql' )
|
|
|
|
|
|
|| ( $dbType === 'sqlite' && $this->db->getFulltextSearchModule() == 'FTS3' );
|
2010-12-14 16:26:35 +00:00
|
|
|
|
|
2013-02-15 10:24:31 +00:00
|
|
|
|
if ( !$dbSupported ) {
|
2010-12-14 16:26:35 +00:00
|
|
|
|
$this->markTestSkipped( "MySQL or SQLite with FTS3 only" );
|
|
|
|
|
|
}
|
2011-06-28 22:26:22 +00:00
|
|
|
|
|
2016-09-16 02:33:52 +00:00
|
|
|
|
$searchType = SearchEngineFactory::getSearchEngineClass( $this->db );
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$this->setMwGlobals( [
|
2018-11-06 13:35:03 +00:00
|
|
|
|
'wgSearchType' => $searchType,
|
|
|
|
|
|
'wgCapitalLinks' => true,
|
|
|
|
|
|
'wgCapitalLinkOverrides' => [
|
|
|
|
|
|
NS_CATEGORY => false // for testCompletionSearchMustRespectCapitalLinkOverrides
|
|
|
|
|
|
]
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] );
|
2014-01-03 01:23:16 +00:00
|
|
|
|
|
2011-06-28 22:26:22 +00:00
|
|
|
|
$this->search = new $searchType( $this->db );
|
2010-12-14 16:26:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-10-08 10:56:20 +00:00
|
|
|
|
protected function tearDown() {
|
|
|
|
|
|
unset( $this->search );
|
2012-12-31 12:54:06 +00:00
|
|
|
|
|
|
|
|
|
|
parent::tearDown();
|
2012-10-08 10:56:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-03-07 17:26:25 +00:00
|
|
|
|
public function addDBDataOnce() {
|
2012-10-12 11:09:08 +00:00
|
|
|
|
if ( !$this->isWikitextNS( NS_MAIN ) ) {
|
2013-05-15 01:12:35 +00:00
|
|
|
|
// @todo cover the case of non-wikitext content in the main namespace
|
2012-10-12 11:09:08 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-06-23 22:38:15 +00:00
|
|
|
|
// Reset the search type back to default - some extensions may have
|
|
|
|
|
|
// overridden it.
|
2018-11-06 13:35:03 +00:00
|
|
|
|
$this->setMwGlobals( [
|
|
|
|
|
|
'wgSearchType' => null,
|
|
|
|
|
|
'wgCapitalLinks' => true,
|
|
|
|
|
|
'wgCapitalLinkOverrides' => [
|
|
|
|
|
|
NS_CATEGORY => false // for testCompletionSearchMustRespectCapitalLinkOverrides
|
|
|
|
|
|
]
|
|
|
|
|
|
] );
|
2016-06-23 22:38:15 +00:00
|
|
|
|
|
2014-09-18 00:02:24 +00:00
|
|
|
|
$this->insertPage( 'Not_Main_Page', 'This is not a main page' );
|
2014-04-24 17:52:34 +00:00
|
|
|
|
$this->insertPage(
|
|
|
|
|
|
'Talk:Not_Main_Page',
|
2014-09-18 00:02:24 +00:00
|
|
|
|
'This is not a talk page to the main page, see [[smithee]]'
|
2014-04-24 17:52:34 +00:00
|
|
|
|
);
|
2014-09-18 00:02:24 +00:00
|
|
|
|
$this->insertPage( 'Smithee', 'A smithee is one who smiths. See also [[Alan Smithee]]' );
|
|
|
|
|
|
$this->insertPage( 'Talk:Smithee', 'This article sucks.' );
|
|
|
|
|
|
$this->insertPage( 'Unrelated_page', 'Nothing in this page is about the S word.' );
|
|
|
|
|
|
$this->insertPage( 'Another_page', 'This page also is unrelated.' );
|
|
|
|
|
|
$this->insertPage( 'Help:Help', 'Help me!' );
|
|
|
|
|
|
$this->insertPage( 'Thppt', 'Blah blah' );
|
|
|
|
|
|
$this->insertPage( 'Alan_Smithee', 'yum' );
|
|
|
|
|
|
$this->insertPage( 'Pages', 'are\'food' );
|
|
|
|
|
|
$this->insertPage( 'HalfOneUp', 'AZ' );
|
|
|
|
|
|
$this->insertPage( 'FullOneUp', 'AZ' );
|
|
|
|
|
|
$this->insertPage( 'HalfTwoLow', 'az' );
|
|
|
|
|
|
$this->insertPage( 'FullTwoLow', 'az' );
|
|
|
|
|
|
$this->insertPage( 'HalfNumbers', '1234567890' );
|
|
|
|
|
|
$this->insertPage( 'FullNumbers', '1234567890' );
|
|
|
|
|
|
$this->insertPage( 'DomainName', 'example.com' );
|
2018-11-06 13:35:03 +00:00
|
|
|
|
$this->insertPage( 'DomainName', 'example.com' );
|
|
|
|
|
|
$this->insertPage( 'Category:search is not Search', '' );
|
|
|
|
|
|
$this->insertPage( 'Category:Search is not search', '' );
|
2010-12-14 16:26:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-01-03 01:23:16 +00:00
|
|
|
|
protected function fetchIds( $results ) {
|
2012-10-12 11:09:08 +00:00
|
|
|
|
if ( !$this->isWikitextNS( NS_MAIN ) ) {
|
|
|
|
|
|
$this->markTestIncomplete( __CLASS__ . " does no yet support non-wikitext content "
|
2013-02-15 10:24:31 +00:00
|
|
|
|
. "in the main namespace" );
|
2012-10-12 11:09:08 +00:00
|
|
|
|
}
|
2010-12-14 16:26:35 +00:00
|
|
|
|
$this->assertTrue( is_object( $results ) );
|
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$matches = [];
|
2018-05-10 22:03:55 +00:00
|
|
|
|
foreach ( $results as $row ) {
|
2010-12-14 16:26:35 +00:00
|
|
|
|
$matches[] = $row->getTitle()->getPrefixedText();
|
|
|
|
|
|
}
|
|
|
|
|
|
$results->free();
|
|
|
|
|
|
# Search is not guaranteed to return results in a certain order;
|
|
|
|
|
|
# sort them numerically so we will compare simply that we received
|
|
|
|
|
|
# the expected matches.
|
|
|
|
|
|
sort( $matches );
|
2013-04-26 12:00:22 +00:00
|
|
|
|
|
2010-12-14 16:26:35 +00:00
|
|
|
|
return $matches;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-10-23 22:51:31 +00:00
|
|
|
|
public function testFullWidth() {
|
2011-06-16 20:57:31 +00:00
|
|
|
|
$this->assertEquals(
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'FullOneUp', 'FullTwoLow', 'HalfOneUp', 'HalfTwoLow' ],
|
2011-06-16 20:57:31 +00:00
|
|
|
|
$this->fetchIds( $this->search->searchText( 'AZ' ) ),
|
|
|
|
|
|
"Search for normalized from Half-width Upper" );
|
|
|
|
|
|
$this->assertEquals(
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'FullOneUp', 'FullTwoLow', 'HalfOneUp', 'HalfTwoLow' ],
|
2011-06-16 20:57:31 +00:00
|
|
|
|
$this->fetchIds( $this->search->searchText( 'az' ) ),
|
|
|
|
|
|
"Search for normalized from Half-width Lower" );
|
|
|
|
|
|
$this->assertEquals(
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'FullOneUp', 'FullTwoLow', 'HalfOneUp', 'HalfTwoLow' ],
|
2011-06-16 20:57:31 +00:00
|
|
|
|
$this->fetchIds( $this->search->searchText( 'AZ' ) ),
|
|
|
|
|
|
"Search for normalized from Full-width Upper" );
|
|
|
|
|
|
$this->assertEquals(
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'FullOneUp', 'FullTwoLow', 'HalfOneUp', 'HalfTwoLow' ],
|
2011-06-16 20:57:31 +00:00
|
|
|
|
$this->fetchIds( $this->search->searchText( 'az' ) ),
|
|
|
|
|
|
"Search for normalized from Full-width Lower" );
|
2010-12-14 16:26:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-10-23 22:51:31 +00:00
|
|
|
|
public function testTextSearch() {
|
2010-12-14 16:26:35 +00:00
|
|
|
|
$this->assertEquals(
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'Smithee' ],
|
2013-02-15 10:24:31 +00:00
|
|
|
|
$this->fetchIds( $this->search->searchText( 'smithee' ) ),
|
2017-06-27 13:58:16 +00:00
|
|
|
|
"Plain search" );
|
2010-12-14 16:26:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-06-29 08:29:13 +00:00
|
|
|
|
public function testWildcardSearch() {
|
|
|
|
|
|
$res = $this->search->searchText( 'smith*' );
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
[ 'Smithee' ],
|
|
|
|
|
|
$this->fetchIds( $res ),
|
|
|
|
|
|
"Search with wildcards" );
|
|
|
|
|
|
|
|
|
|
|
|
$res = $this->search->searchText( 'smithson*' );
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
[],
|
|
|
|
|
|
$this->fetchIds( $res ),
|
|
|
|
|
|
"Search with wildcards must not find unrelated articles" );
|
|
|
|
|
|
|
|
|
|
|
|
$res = $this->search->searchText( 'smith* smithee' );
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
[ 'Smithee' ],
|
|
|
|
|
|
$this->fetchIds( $res ),
|
|
|
|
|
|
"Search with wildcards can be combined with simple terms" );
|
|
|
|
|
|
|
|
|
|
|
|
$res = $this->search->searchText( 'smith* "one who smiths"' );
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
[ 'Smithee' ],
|
|
|
|
|
|
$this->fetchIds( $res ),
|
|
|
|
|
|
"Search with wildcards can be combined with phrase search" );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-06-22 12:48:14 +00:00
|
|
|
|
public function testPhraseSearch() {
|
|
|
|
|
|
$res = $this->search->searchText( '"smithee is one who smiths"' );
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
[ 'Smithee' ],
|
|
|
|
|
|
$this->fetchIds( $res ),
|
2017-06-27 13:58:16 +00:00
|
|
|
|
"Search a phrase" );
|
2017-06-29 08:29:13 +00:00
|
|
|
|
|
|
|
|
|
|
$res = $this->search->searchText( '"smithee is who smiths"' );
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
[],
|
|
|
|
|
|
$this->fetchIds( $res ),
|
|
|
|
|
|
"Phrase search is not sloppy, search terms must be adjacent" );
|
|
|
|
|
|
|
|
|
|
|
|
$res = $this->search->searchText( '"is smithee one who smiths"' );
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
[],
|
|
|
|
|
|
$this->fetchIds( $res ),
|
|
|
|
|
|
"Phrase search is ordered" );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function testPhraseSearchHighlight() {
|
|
|
|
|
|
$phrase = "smithee is one who smiths";
|
|
|
|
|
|
$res = $this->search->searchText( "\"$phrase\"" );
|
2018-05-10 22:03:55 +00:00
|
|
|
|
$match = $res->getIterator()->current();
|
2017-06-29 08:29:13 +00:00
|
|
|
|
$snippet = "A <span class='searchmatch'>" . $phrase . "</span>";
|
|
|
|
|
|
$this->assertStringStartsWith( $snippet,
|
2017-06-22 12:48:14 +00:00
|
|
|
|
$match->getTextSnippet( $res->termMatches() ),
|
2017-06-27 13:58:16 +00:00
|
|
|
|
"Highlight a phrase search" );
|
2017-06-22 12:48:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-10-23 22:51:31 +00:00
|
|
|
|
public function testTextPowerSearch() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$this->search->setNamespaces( [ 0, 1, 4 ] );
|
2010-12-14 16:26:35 +00:00
|
|
|
|
$this->assertEquals(
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[
|
2010-12-14 16:26:35 +00:00
|
|
|
|
'Smithee',
|
|
|
|
|
|
'Talk:Not Main Page',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
2010-12-14 16:26:35 +00:00
|
|
|
|
$this->fetchIds( $this->search->searchText( 'smithee' ) ),
|
2017-06-27 13:58:16 +00:00
|
|
|
|
"Power search" );
|
2010-12-14 16:26:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-10-23 22:51:31 +00:00
|
|
|
|
public function testTitleSearch() {
|
2010-12-14 16:26:35 +00:00
|
|
|
|
$this->assertEquals(
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[
|
2010-12-14 16:26:35 +00:00
|
|
|
|
'Alan Smithee',
|
|
|
|
|
|
'Smithee',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
2010-12-14 16:26:35 +00:00
|
|
|
|
$this->fetchIds( $this->search->searchTitle( 'smithee' ) ),
|
2017-06-27 13:58:16 +00:00
|
|
|
|
"Title search" );
|
2010-12-14 16:26:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-10-23 22:51:31 +00:00
|
|
|
|
public function testTextTitlePowerSearch() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$this->search->setNamespaces( [ 0, 1, 4 ] );
|
2010-12-14 16:26:35 +00:00
|
|
|
|
$this->assertEquals(
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[
|
2010-12-14 16:26:35 +00:00
|
|
|
|
'Alan Smithee',
|
|
|
|
|
|
'Smithee',
|
|
|
|
|
|
'Talk:Smithee',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
2010-12-14 16:26:35 +00:00
|
|
|
|
$this->fetchIds( $this->search->searchTitle( 'smithee' ) ),
|
2017-06-27 13:58:16 +00:00
|
|
|
|
"Title power search" );
|
2010-12-14 16:26:35 +00:00
|
|
|
|
}
|
2014-01-03 01:23:16 +00:00
|
|
|
|
|
2018-11-06 13:35:03 +00:00
|
|
|
|
public function provideCompletionSearchMustRespectCapitalLinkOverrides() {
|
|
|
|
|
|
return [
|
|
|
|
|
|
'Searching for "smithee" finds Smithee on NS_MAIN' => [
|
|
|
|
|
|
'smithee',
|
|
|
|
|
|
'Smithee',
|
|
|
|
|
|
[ NS_MAIN ],
|
|
|
|
|
|
],
|
|
|
|
|
|
'Searching for "search is" will finds "search is not Search" on NS_CATEGORY' => [
|
|
|
|
|
|
'search is',
|
|
|
|
|
|
'Category:search is not Search',
|
|
|
|
|
|
[ NS_CATEGORY ],
|
|
|
|
|
|
],
|
|
|
|
|
|
'Searching for "Search is" will finds "search is not Search" on NS_CATEGORY' => [
|
|
|
|
|
|
'Search is',
|
|
|
|
|
|
'Category:Search is not search',
|
|
|
|
|
|
[ NS_CATEGORY ],
|
|
|
|
|
|
],
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Test that the search query is not munged using wrong CapitalLinks setup
|
|
|
|
|
|
* (in other test that the default search backend can benefit from wgCapitalLinksOverride)
|
|
|
|
|
|
* Guard against regressions like T208255
|
|
|
|
|
|
* @dataProvider provideCompletionSearchMustRespectCapitalLinkOverrides
|
|
|
|
|
|
* @covers SearchEngine::completionSearch
|
|
|
|
|
|
* @covers PrefixSearch::defaultSearchBackend
|
|
|
|
|
|
* @param string $search
|
|
|
|
|
|
* @param string $expectedSuggestion
|
|
|
|
|
|
* @param int[] $namespaces
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testCompletionSearchMustRespectCapitalLinkOverrides(
|
|
|
|
|
|
$search,
|
|
|
|
|
|
$expectedSuggestion,
|
|
|
|
|
|
array $namespaces
|
|
|
|
|
|
) {
|
|
|
|
|
|
$this->search->setNamespaces( $namespaces );
|
|
|
|
|
|
$results = $this->search->completionSearch( $search );
|
|
|
|
|
|
$this->assertEquals( 1, $results->getSize() );
|
|
|
|
|
|
$this->assertEquals( $expectedSuggestion, $results->getSuggestions()[0]->getText() );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-13 00:10:52 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @covers SearchEngine::getSearchIndexFields
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testSearchIndexFields() {
|
|
|
|
|
|
/**
|
2019-02-02 13:39:58 +00:00
|
|
|
|
* @var SearchEngine $mockEngine
|
2016-05-13 00:10:52 +00:00
|
|
|
|
*/
|
2018-01-13 00:02:09 +00:00
|
|
|
|
$mockEngine = $this->getMockBuilder( SearchEngine::class )
|
2017-04-05 23:39:50 +00:00
|
|
|
|
->setMethods( [ 'makeSearchFieldMapping' ] )->getMock();
|
2016-05-13 00:10:52 +00:00
|
|
|
|
|
|
|
|
|
|
$mockFieldBuilder = function ( $name, $type ) {
|
|
|
|
|
|
$mockField =
|
2018-01-13 00:02:09 +00:00
|
|
|
|
$this->getMockBuilder( SearchIndexFieldDefinition::class )->setConstructorArgs( [
|
2016-05-13 00:10:52 +00:00
|
|
|
|
$name,
|
|
|
|
|
|
$type
|
|
|
|
|
|
] )->getMock();
|
2016-08-15 16:37:00 +00:00
|
|
|
|
|
2016-05-13 00:10:52 +00:00
|
|
|
|
$mockField->expects( $this->any() )->method( 'getMapping' )->willReturn( [
|
|
|
|
|
|
'testData' => 'test',
|
|
|
|
|
|
'name' => $name,
|
|
|
|
|
|
'type' => $type,
|
|
|
|
|
|
] );
|
2016-08-15 16:37:00 +00:00
|
|
|
|
|
|
|
|
|
|
$mockField->expects( $this->any() )
|
|
|
|
|
|
->method( 'merge' )
|
|
|
|
|
|
->willReturn( $mockField );
|
|
|
|
|
|
|
2016-05-13 00:10:52 +00:00
|
|
|
|
return $mockField;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
$mockEngine->expects( $this->atLeastOnce() )
|
|
|
|
|
|
->method( 'makeSearchFieldMapping' )
|
|
|
|
|
|
->willReturnCallback( $mockFieldBuilder );
|
|
|
|
|
|
|
|
|
|
|
|
// Not using mock since PHPUnit mocks do not work properly with references in params
|
2016-05-16 20:24:10 +00:00
|
|
|
|
$this->setTemporaryHook( 'SearchIndexFields',
|
|
|
|
|
|
function ( &$fields, SearchEngine $engine ) use ( $mockFieldBuilder ) {
|
|
|
|
|
|
$fields['testField'] =
|
|
|
|
|
|
$mockFieldBuilder( "testField", SearchIndexField::INDEX_TYPE_TEXT );
|
|
|
|
|
|
return true;
|
|
|
|
|
|
} );
|
2016-05-13 00:10:52 +00:00
|
|
|
|
|
|
|
|
|
|
$fields = $mockEngine->getSearchIndexFields();
|
|
|
|
|
|
$this->assertArrayHasKey( 'language', $fields );
|
|
|
|
|
|
$this->assertArrayHasKey( 'category', $fields );
|
2018-01-13 00:02:09 +00:00
|
|
|
|
$this->assertInstanceOf( SearchIndexField::class, $fields['testField'] );
|
2016-05-13 00:10:52 +00:00
|
|
|
|
|
|
|
|
|
|
$mapping = $fields['testField']->getMapping( $mockEngine );
|
|
|
|
|
|
$this->assertArrayHasKey( 'testData', $mapping );
|
|
|
|
|
|
$this->assertEquals( 'test', $mapping['testData'] );
|
|
|
|
|
|
}
|
2016-04-26 22:19:58 +00:00
|
|
|
|
|
|
|
|
|
|
public function hookSearchIndexFields( $mockFieldBuilder, &$fields, SearchEngine $engine ) {
|
|
|
|
|
|
$fields['testField'] = $mockFieldBuilder( "testField", SearchIndexField::INDEX_TYPE_TEXT );
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function testAugmentorSearch() {
|
|
|
|
|
|
$this->search->setNamespaces( [ 0, 1, 4 ] );
|
|
|
|
|
|
$resultSet = $this->search->searchText( 'smithee' );
|
|
|
|
|
|
// Not using mock since PHPUnit mocks do not work properly with references in params
|
|
|
|
|
|
$this->mergeMwGlobalArrayValue( 'wgHooks',
|
|
|
|
|
|
[ 'SearchResultsAugment' => [ [ $this, 'addAugmentors' ] ] ] );
|
|
|
|
|
|
$this->search->augmentSearchResults( $resultSet );
|
2018-05-10 22:03:55 +00:00
|
|
|
|
foreach ( $resultSet as $result ) {
|
2016-04-26 22:19:58 +00:00
|
|
|
|
$id = $result->getTitle()->getArticleID();
|
|
|
|
|
|
$augmentData = "Result:$id:" . $result->getTitle()->getText();
|
|
|
|
|
|
$augmentData2 = "Result2:$id:" . $result->getTitle()->getText();
|
|
|
|
|
|
$this->assertEquals( [ 'testSet' => $augmentData, 'testRow' => $augmentData2 ],
|
|
|
|
|
|
$result->getExtensionData() );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function addAugmentors( &$setAugmentors, &$rowAugmentors ) {
|
2018-01-13 00:02:09 +00:00
|
|
|
|
$setAugmentor = $this->createMock( ResultSetAugmentor::class );
|
2016-04-26 22:19:58 +00:00
|
|
|
|
$setAugmentor->expects( $this->once() )
|
|
|
|
|
|
->method( 'augmentAll' )
|
|
|
|
|
|
->willReturnCallback( function ( SearchResultSet $resultSet ) {
|
|
|
|
|
|
$data = [];
|
2018-05-10 22:03:55 +00:00
|
|
|
|
foreach ( $resultSet as $result ) {
|
2016-04-26 22:19:58 +00:00
|
|
|
|
$id = $result->getTitle()->getArticleID();
|
|
|
|
|
|
$data[$id] = "Result:$id:" . $result->getTitle()->getText();
|
|
|
|
|
|
}
|
|
|
|
|
|
return $data;
|
|
|
|
|
|
} );
|
|
|
|
|
|
$setAugmentors['testSet'] = $setAugmentor;
|
|
|
|
|
|
|
2018-01-13 00:02:09 +00:00
|
|
|
|
$rowAugmentor = $this->createMock( ResultAugmentor::class );
|
2016-04-26 22:19:58 +00:00
|
|
|
|
$rowAugmentor->expects( $this->exactly( 2 ) )
|
|
|
|
|
|
->method( 'augment' )
|
|
|
|
|
|
->willReturnCallback( function ( SearchResult $result ) {
|
|
|
|
|
|
$id = $result->getTitle()->getArticleID();
|
|
|
|
|
|
return "Result2:$id:" . $result->getTitle()->getText();
|
|
|
|
|
|
} );
|
|
|
|
|
|
$rowAugmentors['testRow'] = $rowAugmentor;
|
|
|
|
|
|
}
|
2017-12-14 01:03:20 +00:00
|
|
|
|
|
|
|
|
|
|
public function testFiltersMissing() {
|
|
|
|
|
|
$availableResults = [];
|
|
|
|
|
|
foreach ( range( 0, 11 ) as $i ) {
|
|
|
|
|
|
$title = "Search_Result_$i";
|
|
|
|
|
|
$availableResults[] = $title;
|
|
|
|
|
|
// pages not created must be filtered
|
|
|
|
|
|
if ( $i % 2 == 0 ) {
|
2018-07-24 14:50:03 +00:00
|
|
|
|
$this->editSearchResultPage( $title );
|
2017-12-14 01:03:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
MockCompletionSearchEngine::addMockResults( 'foo', $availableResults );
|
|
|
|
|
|
|
|
|
|
|
|
$engine = new MockCompletionSearchEngine();
|
|
|
|
|
|
$engine->setLimitOffset( 10, 0 );
|
|
|
|
|
|
$results = $engine->completionSearch( 'foo' );
|
|
|
|
|
|
$this->assertEquals( 5, $results->getSize() );
|
|
|
|
|
|
$this->assertTrue( $results->hasMoreResults() );
|
|
|
|
|
|
|
|
|
|
|
|
$engine->setLimitOffset( 10, 10 );
|
|
|
|
|
|
$results = $engine->completionSearch( 'foo' );
|
|
|
|
|
|
$this->assertEquals( 1, $results->getSize() );
|
|
|
|
|
|
$this->assertFalse( $results->hasMoreResults() );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-07-24 14:50:03 +00:00
|
|
|
|
private function editSearchResultPage( $title ) {
|
2017-12-14 01:03:20 +00:00
|
|
|
|
$page = WikiPage::factory( Title::newFromText( $title ) );
|
|
|
|
|
|
$page->doEditContent(
|
|
|
|
|
|
new WikitextContent( 'UTContent' ),
|
|
|
|
|
|
'UTPageSummary',
|
|
|
|
|
|
EDIT_NEW | EDIT_SUPPRESS_RC
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2018-07-09 16:55:54 +00:00
|
|
|
|
|
|
|
|
|
|
public function provideDataForParseNamespacePrefix() {
|
|
|
|
|
|
return [
|
|
|
|
|
|
'noop' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'query' => 'foo',
|
|
|
|
|
|
],
|
|
|
|
|
|
false
|
|
|
|
|
|
],
|
|
|
|
|
|
'empty' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'query' => '',
|
|
|
|
|
|
],
|
|
|
|
|
|
false,
|
|
|
|
|
|
],
|
|
|
|
|
|
'namespace prefix' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'query' => 'help:test',
|
|
|
|
|
|
],
|
|
|
|
|
|
[ 'test', [ NS_HELP ] ],
|
|
|
|
|
|
],
|
|
|
|
|
|
'accented namespace prefix with hook' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'query' => 'hélp:test',
|
|
|
|
|
|
'withHook' => true,
|
|
|
|
|
|
],
|
|
|
|
|
|
[ 'test', [ NS_HELP ] ],
|
|
|
|
|
|
],
|
|
|
|
|
|
'accented namespace prefix without hook' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'query' => 'hélp:test',
|
|
|
|
|
|
'withHook' => false,
|
|
|
|
|
|
],
|
|
|
|
|
|
false,
|
|
|
|
|
|
],
|
|
|
|
|
|
'all with all keyword allowed' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'query' => 'all:test',
|
|
|
|
|
|
'withAll' => true,
|
|
|
|
|
|
],
|
|
|
|
|
|
[ 'test', null ],
|
|
|
|
|
|
],
|
|
|
|
|
|
'all with all keyword disallowed' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'query' => 'all:test',
|
|
|
|
|
|
'withAll' => false,
|
|
|
|
|
|
],
|
|
|
|
|
|
false
|
|
|
|
|
|
],
|
|
|
|
|
|
'ns only' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'query' => 'help:',
|
|
|
|
|
|
],
|
|
|
|
|
|
[ '', [ NS_HELP ] ]
|
|
|
|
|
|
],
|
|
|
|
|
|
'all only' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'query' => 'all:',
|
|
|
|
|
|
'withAll' => true,
|
|
|
|
|
|
],
|
|
|
|
|
|
[ '', null ]
|
|
|
|
|
|
],
|
|
|
|
|
|
'all wins over namespace when first' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'query' => 'all:help:test',
|
|
|
|
|
|
'withAll' => true,
|
|
|
|
|
|
],
|
|
|
|
|
|
[ 'help:test', null ]
|
|
|
|
|
|
],
|
|
|
|
|
|
'ns wins over all when first' => [
|
|
|
|
|
|
[
|
|
|
|
|
|
'query' => 'help:all:test',
|
|
|
|
|
|
'withAll' => true,
|
|
|
|
|
|
],
|
|
|
|
|
|
[ 'all:test', [ NS_HELP ] ]
|
|
|
|
|
|
],
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider provideDataForParseNamespacePrefix
|
|
|
|
|
|
* @param array $params
|
|
|
|
|
|
* @param array|false $expected
|
|
|
|
|
|
* @throws FatalError
|
|
|
|
|
|
* @throws MWException
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testParseNamespacePrefix( array $params, $expected ) {
|
|
|
|
|
|
$this->setTemporaryHook( 'PrefixSearchExtractNamespace', function ( &$namespaces, &$query ) {
|
|
|
|
|
|
if ( strpos( $query, 'hélp:' ) === 0 ) {
|
|
|
|
|
|
$namespaces = [ NS_HELP ];
|
|
|
|
|
|
$query = substr( $query, strlen( 'hélp:' ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
} );
|
|
|
|
|
|
$testSet = [];
|
|
|
|
|
|
if ( isset( $params['withAll'] ) && isset( $params['withHook'] ) ) {
|
|
|
|
|
|
$testSet[] = $params;
|
|
|
|
|
|
} elseif ( isset( $params['withAll'] ) ) {
|
|
|
|
|
|
$testSet[] = $params + [ 'withHook' => true ];
|
|
|
|
|
|
$testSet[] = $params + [ 'withHook' => false ];
|
|
|
|
|
|
} elseif ( isset( $params['withHook'] ) ) {
|
|
|
|
|
|
$testSet[] = $params + [ 'withAll' => true ];
|
|
|
|
|
|
$testSet[] = $params + [ 'withAll' => false ];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$testSet[] = $params + [ 'withAll' => true, 'withHook' => true ];
|
|
|
|
|
|
$testSet[] = $params + [ 'withAll' => true, 'withHook' => false ];
|
|
|
|
|
|
$testSet[] = $params + [ 'withAll' => false, 'withHook' => false ];
|
|
|
|
|
|
$testSet[] = $params + [ 'withAll' => true, 'withHook' => false ];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach ( $testSet as $test ) {
|
|
|
|
|
|
$actual = SearchEngine::parseNamespacePrefixes( $test['query'],
|
|
|
|
|
|
$test['withAll'], $test['withHook'] );
|
|
|
|
|
|
$this->assertEquals( $expected, $actual, 'with params: ' . print_r( $test, true ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2010-12-14 16:26:35 +00:00
|
|
|
|
}
|