1<?php
2
3namespace MediaWiki\Tests\Unit\Permissions;
4
5use MediaWiki\Block\Block;
6use MediaWiki\Permissions\Authority;
7use MediaWiki\Permissions\SimpleAuthority;
8use MediaWiki\Permissions\UltimateAuthority;
9use MediaWiki\User\UserIdentity;
10use MediaWiki\User\UserIdentityValue;
11
12/**
13 * Various useful Authority mocks.
14 * @stable to use (since 1.37)
15 */
16trait MockAuthorityTrait {
17
18	/**
19	 * Create mock ultimate Authority for anon user.
20	 *
21	 * @return Authority
22	 */
23	private function mockAnonUltimateAuthority(): Authority {
24		return new UltimateAuthority( new UserIdentityValue( 0, '127.0.0.1' ) );
25	}
26
27	/**
28	 * Create mock ultimate Authority for registered user.
29	 *
30	 * @return Authority
31	 */
32	private function mockRegisteredUltimateAuthority(): Authority {
33		return new UltimateAuthority( new UserIdentityValue( 9999, 'Petr' ) );
34	}
35
36	/**
37	 * Create mock Authority for anon user with no permissions.
38	 *
39	 * @return Authority
40	 */
41	private function mockAnonNullAuthority(): Authority {
42		return new SimpleAuthority( new UserIdentityValue( 0, '127.0.0.1' ), [] );
43	}
44
45	/**
46	 * Create mock Authority for a registered user with no permissions.
47	 *
48	 * @return Authority
49	 */
50	private function mockRegisteredNullAuthority(): Authority {
51		return new SimpleAuthority( new UserIdentityValue( 9999, 'Petr' ), [] );
52	}
53
54	/**
55	 * Create a mock Authority for anon user with $permissions.
56	 *
57	 * @param array $permissions
58	 * @return Authority
59	 */
60	private function mockAnonAuthorityWithPermissions( array $permissions ): Authority {
61		return new SimpleAuthority( new UserIdentityValue( 0, '127.0.0.1' ), $permissions );
62	}
63
64	/**
65	 * Create a mock Authority for a registered user with $permissions.
66	 *
67	 * @param array $permissions
68	 * @return Authority
69	 */
70	private function mockRegisteredAuthorityWithPermissions( array $permissions ): Authority {
71		return new SimpleAuthority( new UserIdentityValue( 9999, 'Petr' ), $permissions );
72	}
73
74	/**
75	 * Create a mock Authority for a $user with $permissions.
76	 *
77	 * @param UserIdentity $user
78	 * @param array $permissions
79	 * @return Authority
80	 */
81	private function mockUserAuthorityWithPermissions(
82		UserIdentity $user,
83		array $permissions
84	): Authority {
85		return new SimpleAuthority( $user, $permissions );
86	}
87
88	/**
89	 * Create a mock Authority for $user with $block and $permissions.
90	 *
91	 * @param UserIdentity $user
92	 * @param Block $block
93	 * @param array $permissions
94	 *
95	 * @return Authority
96	 */
97	private function mockUserAuthorityWithBlock(
98		UserIdentity $user,
99		Block $block,
100		array $permissions = []
101	): Authority {
102		return $this->mockAuthority(
103			$user,
104			static function ( $permission ) use ( $permissions ) {
105				return in_array( $permission, $permissions );
106			},
107			$block
108		);
109	}
110
111	/**
112	 * Create a mock Authority for an anon user with all but $permissions
113	 * @param array $permissions
114	 * @return Authority
115	 */
116	private function mockAnonAuthorityWithoutPermissions( array $permissions ): Authority {
117		return $this->mockUserAuthorityWithoutPermissions(
118			new UserIdentityValue( 0, '127.0.0.1' ),
119			$permissions
120		);
121	}
122
123	/**
124	 * Create a mock Authority for a registered user with all but $permissions
125	 * @param array $permissions
126	 * @return Authority
127	 */
128	private function mockRegisteredAuthorityWithoutPermissions( array $permissions ): Authority {
129		return $this->mockUserAuthorityWithoutPermissions(
130			new UserIdentityValue( 9999, 'Petr' ),
131			$permissions
132		);
133	}
134
135	/**
136	 * Create a mock Authority for a $user with all but $permissions
137	 * @param UserIdentity $user
138	 * @param array $permissions
139	 * @return Authority
140	 */
141	private function mockUserAuthorityWithoutPermissions(
142		UserIdentity $user,
143		array $permissions
144	): Authority {
145		return $this->mockAuthority(
146			$user,
147			static function ( $permission ) use ( $permissions ) {
148				return !in_array( $permission, $permissions );
149			}
150		);
151	}
152
153	/**
154	 * Create mock Authority for anon user where permissions are determined by $callback.
155	 *
156	 * @param callable $permissionCallback
157	 * @return Authority
158	 */
159	private function mockAnonAuthority( callable $permissionCallback ): Authority {
160		return $this->mockAuthority(
161			new UserIdentityValue( 0, '127.0.0.1' ),
162			$permissionCallback
163		);
164	}
165
166	/**
167	 * Create mock Authority for registered user where permissions are determined by $callback.
168	 *
169	 * @param callable $permissionCallback
170	 * @return Authority
171	 */
172	private function mockRegisteredAuthority( callable $permissionCallback ): Authority {
173		return $this->mockAuthority(
174			new UserIdentityValue( 9999, 'Petr' ),
175			$permissionCallback
176		);
177	}
178
179	/**
180	 * Create mock Authority for $user where permissions are determined by $callback.
181	 *
182	 * @param UserIdentity $user
183	 * @param callable $permissionCallback ( string $permission, ?PageIdentity $page )
184	 * @param Block|null $block
185	 *
186	 * @return Authority
187	 */
188	private function mockAuthority(
189		UserIdentity $user,
190		callable $permissionCallback,
191		Block $block = null
192	): Authority {
193		$mock = $this->createMock( Authority::class );
194		$mock->method( 'getUser' )->willReturn( $user );
195		$methods = [ 'isAllowed', 'probablyCan', 'definitelyCan', 'authorizeRead', 'authorizeWrite' ];
196		foreach ( $methods as $method ) {
197			$mock->method( $method )->willReturnCallback( $permissionCallback );
198		}
199		$mock->method( 'isAllowedAny' )
200			->willReturnCallback( static function ( ...$permissions ) use ( $permissionCallback ) {
201				foreach ( $permissions as $permission ) {
202					if ( $permissionCallback( $permission ) ) {
203						return true;
204					}
205				}
206				return false;
207			} );
208		$mock->method( 'isAllowedAll' )
209			->willReturnCallback( static function ( ...$permissions ) use ( $permissionCallback ) {
210				foreach ( $permissions as $permission ) {
211					if ( !$permissionCallback( $permission ) ) {
212						return false;
213					}
214				}
215				return true;
216			} );
217		$mock->method( 'getBlock' )->willReturn( $block );
218		return $mock;
219	}
220}
221