1<?php 2 3namespace MediaWiki\Tests\User; 4 5use InvalidArgumentException; 6use MediaWiki\Tests\Unit\DummyServicesTrait; 7use MediaWiki\User\UserFactory; 8use MediaWiki\User\UserNamePrefixSearch; 9use MediaWiki\User\UserNameUtils; 10use MediaWikiUnitTestCase; 11use User; 12use Wikimedia\Rdbms\Database; 13use Wikimedia\Rdbms\LoadBalancer; 14 15/** 16 * @covers MediaWiki\User\UserNamePrefixSearch 17 * @author DannyS712 18 */ 19class UserNamePrefixSearchTest extends MediaWikiUnitTestCase { 20 use DummyServicesTrait; 21 22 /** 23 * @dataProvider provideTestSearch 24 * @param int $audienceType 1='public', 2=user without `hideuser` rights, 3=user with `hideuser` rights 25 * @param string $prefix 26 * @param int $limit 27 * @param int $offset 28 * @param array $result 29 */ 30 public function testSearch( int $audienceType, $prefix, int $limit, int $offset, array $result ) { 31 $userNameUtils = $this->getDummyUserNameUtils(); 32 33 if ( $audienceType === 1 ) { 34 // 'public' audience 35 $audience = UserNamePrefixSearch::AUDIENCE_PUBLIC; 36 $excludeHidden = true; 37 } else { 38 if ( $audienceType === 2 ) { 39 // no hideuser rights 40 $hasHideuser = false; 41 $excludeHidden = true; 42 } else { 43 // 3 - has hideuser rights 44 $hasHideuser = true; 45 $excludeHidden = false; 46 } 47 // specific to a user identity 48 $audience = $this->createMock( User::class ); 49 $audience->method( 'isAllowed' ) 50 ->with( 'hideuser' ) 51 ->willReturn( $hasHideuser ); 52 } 53 54 $database = $this->createMock( Database::class ); 55 $database->expects( $this->once() ) 56 ->method( 'anyString' ) 57 ->willReturn( 'anyStringGoesHere' ); 58 $database->expects( $this->once() ) 59 ->method( 'buildLike' ) 60 ->with( $prefix, 'anyStringGoesHere' ) 61 ->willReturn( 'LIKE ' . $prefix . 'anyStringGoesHere' ); 62 63 // Query parameters 64 $tables = [ 'user' ]; 65 $conds = [ 'user_name LIKE ' . $prefix . 'anyStringGoesHere' ]; 66 $joinConds = []; 67 if ( $excludeHidden ) { 68 $tables[] = 'ipblocks'; 69 $conds['ipb_deleted'] = [ 0, null ]; 70 $joinConds['ipblocks'] = [ 'LEFT JOIN', 'user_id=ipb_user' ]; 71 } 72 $options = [ 73 'LIMIT' => $limit, 74 'ORDER BY' => 'user_name', 75 'OFFSET' => $offset 76 ]; 77 $database->expects( $this->once() ) 78 ->method( 'selectFieldValues' ) 79 ->with( 80 $tables, 81 'user_name', 82 $conds, 83 'MediaWiki\User\UserNamePrefixSearch::search', 84 $options, 85 $joinConds 86 ) 87 ->willReturn( $result ); 88 89 $loadBalancer = $this->createMock( LoadBalancer::class ); 90 $loadBalancer->expects( $this->once() ) 91 ->method( 'getConnectionRef' ) 92 ->with( DB_REPLICA ) 93 ->willReturn( $database ); 94 95 $userNamePrefixSearch = new UserNamePrefixSearch( 96 $loadBalancer, 97 $this->createNoOpMock( UserFactory::class ), 98 $userNameUtils 99 ); 100 $res = $userNamePrefixSearch->search( 101 $audience, 102 $prefix, 103 $limit, 104 $offset 105 ); 106 $this->assertSame( $result, $res ); 107 } 108 109 public function provideTestSearch() { 110 // [ $audienceType, $prefix, $limit, $offset, $result ] 111 return [ 112 'public' => [ 113 1, 114 '', 115 10, 116 0, 117 [ 'public result goes here' ] 118 ], 119 'user without hideuser rights' => [ 120 2, 121 'Prefix', 122 10, 123 5, 124 [ 'public result goes here, since user cannot see anything hidden' ] 125 ], 126 'user with hideuser rights' => [ 127 3, 128 'AnotherPrefix', 129 15, 130 2, 131 [ 132 'result that is public', 133 'also a result that is private' 134 ] 135 ], 136 ]; 137 } 138 139 public function testSearchInvalidAudience() { 140 $userNamePrefixSearch = new UserNamePrefixSearch( 141 $this->createMock( LoadBalancer::class ), 142 $this->createMock( UserFactory::class ), 143 $this->createMock( UserNameUtils::class ) 144 ); 145 146 $this->expectException( InvalidArgumentException::class ); 147 $this->expectExceptionMessage( '$audience must be AUDIENCE_PUBLIC or an Authority object' ); 148 $userNamePrefixSearch->search( 149 'ThisIsTheInvalidAudience', 150 '', 151 1, 152 0 153 ); 154 } 155 156} 157