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