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