123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- <?php
- use Wikimedia\TestingAccessWrapper;
- /**
- * @group Search
- * @group Database
- * @covers PrefixSearch
- */
- class PrefixSearchTest extends MediaWikiLangTestCase {
- const NS_NONCAP = 12346;
- private $originalHandlers;
- public function addDBDataOnce() {
- if ( !$this->isWikitextNS( NS_MAIN ) ) {
- // tests are skipped if NS_MAIN is not wikitext
- return;
- }
- $this->insertPage( 'Sandbox' );
- $this->insertPage( 'Bar' );
- $this->insertPage( 'Example' );
- $this->insertPage( 'Example Bar' );
- $this->insertPage( 'Example Foo' );
- $this->insertPage( 'Example Foo/Bar' );
- $this->insertPage( 'Example/Baz' );
- $this->insertPage( 'Redirect test', '#REDIRECT [[Redirect Test]]' );
- $this->insertPage( 'Redirect Test' );
- $this->insertPage( 'Redirect Test Worse Result' );
- $this->insertPage( 'Redirect test2', '#REDIRECT [[Redirect Test2]]' );
- $this->insertPage( 'Redirect TEST2', '#REDIRECT [[Redirect Test2]]' );
- $this->insertPage( 'Redirect Test2' );
- $this->insertPage( 'Redirect Test2 Worse Result' );
- $this->insertPage( 'Talk:Sandbox' );
- $this->insertPage( 'Talk:Example' );
- $this->insertPage( 'User:Example' );
- $this->insertPage( Title::makeTitle( self::NS_NONCAP, 'Bar' ) );
- $this->insertPage( Title::makeTitle( self::NS_NONCAP, 'Upper' ) );
- $this->insertPage( Title::makeTitle( self::NS_NONCAP, 'sandbox' ) );
- }
- protected function setUp() {
- parent::setUp();
- if ( !$this->isWikitextNS( NS_MAIN ) ) {
- $this->markTestSkipped( 'Main namespace does not support wikitext.' );
- }
- // Avoid special pages from extensions interfering with the tests
- $this->setMwGlobals( [
- 'wgSpecialPages' => [],
- 'wgHooks' => [],
- 'wgExtraNamespaces' => [ self::NS_NONCAP => 'NonCap' ],
- 'wgCapitalLinkOverrides' => [ self::NS_NONCAP => false ],
- ] );
- $this->originalHandlers = TestingAccessWrapper::newFromClass( Hooks::class )->handlers;
- TestingAccessWrapper::newFromClass( Hooks::class )->handlers = [];
- $this->overrideMwServices();
- }
- public function tearDown() {
- parent::tearDown();
- TestingAccessWrapper::newFromClass( Hooks::class )->handlers = $this->originalHandlers;
- }
- protected function searchProvision( array $results = null ) {
- if ( $results === null ) {
- $this->setMwGlobals( 'wgHooks', [] );
- } else {
- $this->setMwGlobals( 'wgHooks', [
- 'PrefixSearchBackend' => [
- function ( $namespaces, $search, $limit, &$srchres ) use ( $results ) {
- $srchres = $results;
- return false;
- }
- ],
- ] );
- }
- }
- public static function provideSearch() {
- return [
- [ [
- 'Empty string',
- 'query' => '',
- 'results' => [],
- ] ],
- [ [
- 'Main namespace with title prefix',
- 'query' => 'Ex',
- 'results' => [
- 'Example',
- 'Example/Baz',
- 'Example Bar',
- ],
- // Third result when testing offset
- 'offsetresult' => [
- 'Example Foo',
- ],
- ] ],
- [ [
- 'Talk namespace prefix',
- 'query' => 'Talk:',
- 'results' => [
- 'Talk:Example',
- 'Talk:Sandbox',
- ],
- ] ],
- [ [
- 'User namespace prefix',
- 'query' => 'User:',
- 'results' => [
- 'User:Example',
- ],
- ] ],
- [ [
- 'Special namespace prefix',
- 'query' => 'Special:',
- 'results' => [
- 'Special:ActiveUsers',
- 'Special:AllMessages',
- 'Special:AllMyUploads',
- ],
- // Third result when testing offset
- 'offsetresult' => [
- 'Special:AllPages',
- ],
- ] ],
- [ [
- 'Special namespace with prefix',
- 'query' => 'Special:Un',
- 'results' => [
- 'Special:Unblock',
- 'Special:UncategorizedCategories',
- 'Special:UncategorizedFiles',
- ],
- // Third result when testing offset
- 'offsetresult' => [
- 'Special:UncategorizedPages',
- ],
- ] ],
- [ [
- 'Special page name',
- 'query' => 'Special:EditWatchlist',
- 'results' => [
- 'Special:EditWatchlist',
- ],
- ] ],
- [ [
- 'Special page subpages',
- 'query' => 'Special:EditWatchlist/',
- 'results' => [
- 'Special:EditWatchlist/clear',
- 'Special:EditWatchlist/raw',
- ],
- ] ],
- [ [
- 'Special page subpages with prefix',
- 'query' => 'Special:EditWatchlist/cl',
- 'results' => [
- 'Special:EditWatchlist/clear',
- ],
- ] ],
- [ [
- 'Namespace with case sensitive first letter',
- 'query' => 'NonCap:upper',
- 'results' => []
- ] ],
- [ [
- 'Multinamespace search',
- 'query' => 'B',
- 'results' => [
- 'Bar',
- 'NonCap:Bar',
- ],
- 'namespaces' => [ NS_MAIN, self::NS_NONCAP ],
- ] ],
- [ [
- 'Multinamespace search with lowercase first letter',
- 'query' => 'sand',
- 'results' => [
- 'Sandbox',
- 'NonCap:sandbox',
- ],
- 'namespaces' => [ NS_MAIN, self::NS_NONCAP ],
- ] ],
- ];
- }
- /**
- * @dataProvider provideSearch
- * @covers PrefixSearch::search
- * @covers PrefixSearch::searchBackend
- */
- public function testSearch( array $case ) {
- // FIXME: fails under postgres
- $this->markTestSkippedIfDbType( 'postgres' );
- $this->searchProvision( null );
- $namespaces = $case['namespaces'] ?? [];
- if ( wfGetDB( DB_REPLICA )->getType() === 'postgres' ) {
- // Postgres will sort lexicographically on utf8 code units (" " before "/")
- sort( $case['results'], SORT_STRING );
- }
- $searcher = new StringPrefixSearch;
- $results = $searcher->search( $case['query'], 3, $namespaces );
- $this->assertEquals(
- $case['results'],
- $results,
- $case[0]
- );
- }
- /**
- * @dataProvider provideSearch
- * @covers PrefixSearch::search
- * @covers PrefixSearch::searchBackend
- */
- public function testSearchWithOffset( array $case ) {
- // FIXME: fails under postgres
- $this->markTestSkippedIfDbType( 'postgres' );
- $this->searchProvision( null );
- $namespaces = $case['namespaces'] ?? [];
- $searcher = new StringPrefixSearch;
- $results = $searcher->search( $case['query'], 3, $namespaces, 1 );
- if ( wfGetDB( DB_REPLICA )->getType() === 'postgres' ) {
- // Postgres will sort lexicographically on utf8 code units (" " before "/")
- sort( $case['results'], SORT_STRING );
- }
- // We don't expect the first result when offsetting
- array_shift( $case['results'] );
- // And sometimes we expect a different last result
- $expected = isset( $case['offsetresult'] ) ?
- array_merge( $case['results'], $case['offsetresult'] ) :
- $case['results'];
- $this->assertEquals(
- $expected,
- $results,
- $case[0]
- );
- }
- public static function provideSearchBackend() {
- return [
- [ [
- 'Simple case',
- 'provision' => [
- 'Bar',
- 'Barcelona',
- 'Barbara',
- ],
- 'query' => 'Bar',
- 'results' => [
- 'Bar',
- 'Barcelona',
- 'Barbara',
- ],
- ] ],
- [ [
- 'Exact match not on top (T72958)',
- 'provision' => [
- 'Barcelona',
- 'Bar',
- 'Barbara',
- ],
- 'query' => 'Bar',
- 'results' => [
- 'Bar',
- 'Barcelona',
- 'Barbara',
- ],
- ] ],
- [ [
- 'Exact match missing (T72958)',
- 'provision' => [
- 'Barcelona',
- 'Barbara',
- 'Bart',
- ],
- 'query' => 'Bar',
- 'results' => [
- 'Bar',
- 'Barcelona',
- 'Barbara',
- ],
- ] ],
- [ [
- 'Exact match missing and not existing',
- 'provision' => [
- 'Exile',
- 'Exist',
- 'External',
- ],
- 'query' => 'Ex',
- 'results' => [
- 'Exile',
- 'Exist',
- 'External',
- ],
- ] ],
- [ [
- "Exact match shouldn't override already found match if " .
- "exact is redirect and found isn't",
- 'provision' => [
- // Target of the exact match is low in the list
- 'Redirect Test Worse Result',
- 'Redirect Test',
- ],
- 'query' => 'redirect test',
- 'results' => [
- // Redirect target is pulled up and exact match isn't added
- 'Redirect Test',
- 'Redirect Test Worse Result',
- ],
- ] ],
- [ [
- "Exact match shouldn't override already found match if " .
- "both exact match and found match are redirect",
- 'provision' => [
- // Another redirect to the same target as the exact match
- // is low in the list
- 'Redirect Test2 Worse Result',
- 'Redirect test2',
- ],
- 'query' => 'redirect TEST2',
- 'results' => [
- // Found redirect is pulled to the top and exact match isn't
- // added
- 'Redirect test2',
- 'Redirect Test2 Worse Result',
- ],
- ] ],
- [ [
- "Exact match should override any already found matches that " .
- "are redirects to it",
- 'provision' => [
- // Another redirect to the same target as the exact match
- // is low in the list
- 'Redirect Test Worse Result',
- 'Redirect test',
- ],
- 'query' => 'Redirect Test',
- 'results' => [
- // Found redirect is pulled to the top and exact match isn't
- // added
- 'Redirect Test',
- 'Redirect Test Worse Result',
- ],
- ] ],
- ];
- }
- /**
- * @dataProvider provideSearchBackend
- * @covers PrefixSearch::searchBackend
- */
- public function testSearchBackend( array $case ) {
- $this->searchProvision( $case['provision'] );
- $searcher = new StringPrefixSearch;
- $results = $searcher->search( $case['query'], 3 );
- $this->assertEquals(
- $case['results'],
- $results,
- $case[0]
- );
- }
- }
|