SECURITY: blacklist CSS var()
[lhc/web/wiklou.git] / tests / phpunit / includes / TestUserRegistry.php
1 <?php
2
3 /**
4 * @since 1.28
5 */
6 class TestUserRegistry {
7
8 /** @var TestUser[] (group key => TestUser) */
9 private static $testUsers = [];
10
11 /** @var int Count of users that have been generated */
12 private static $counter = 0;
13
14 /** @var int Random int, included in IDs */
15 private static $randInt;
16
17 public static function getNextId() {
18 if ( !self::$randInt ) {
19 self::$randInt = mt_rand( 1, 0xFFFFFF );
20 }
21 return sprintf( '%06x.%03x', self::$randInt, ++self::$counter );
22 }
23
24 /**
25 * Get a TestUser object that the caller may modify.
26 *
27 * @since 1.28
28 *
29 * @param string $testName Caller's __CLASS__. Used to generate the
30 * user's username.
31 * @param string|string[] $groups Groups the test user should be added to.
32 * @return TestUser
33 */
34 public static function getMutableTestUser( $testName, $groups = [] ) {
35 $id = self::getNextId();
36 $password = "password_for_test_user_id_{$id}";
37 $testUser = new TestUser(
38 "TestUser $testName $id", // username
39 "Name $id", // real name
40 "$id@mediawiki.test", // e-mail
41 (array)$groups, // groups
42 $password // password
43 );
44 $testUser->getUser()->clearInstanceCache();
45 return $testUser;
46 }
47
48 /**
49 * Get a TestUser object that the caller may not modify.
50 *
51 * Whenever possible, unit tests should use immutable users, because
52 * immutable users can be reused in multiple tests, which helps keep
53 * the unit tests fast.
54 *
55 * @since 1.28
56 *
57 * @param string|string[] $groups Groups the test user should be added to.
58 * @return TestUser
59 */
60 public static function getImmutableTestUser( $groups = [] ) {
61 $groups = array_unique( (array)$groups );
62 sort( $groups );
63 $key = implode( ',', $groups );
64
65 $testUser = self::$testUsers[$key] ?? false;
66
67 if ( !$testUser || !$testUser->getUser()->isLoggedIn() ) {
68 $id = self::getNextId();
69 // Hack! If this is the primary sysop account, make the username
70 // be 'UTSysop', for back-compat, and for the sake of PHPUnit data
71 // provider methods, which are executed before the test database
72 // is set up. See T136348.
73 if ( $groups === [ 'bureaucrat', 'sysop' ] ) {
74 $username = 'UTSysop';
75 $password = 'UTSysopPassword';
76 } else {
77 $username = "TestUser $id";
78 $password = "password_for_test_user_id_{$id}";
79 }
80 self::$testUsers[$key] = $testUser = new TestUser(
81 $username, // username
82 "Name $id", // real name
83 "$id@mediawiki.test", // e-mail
84 $groups, // groups
85 $password // password
86 );
87 }
88
89 $testUser->getUser()->clearInstanceCache();
90 return self::$testUsers[$key];
91 }
92
93 /**
94 * Clear the registry.
95 *
96 * TestUsers created by this class will not be deleted, but any handles
97 * to existing immutable TestUsers will be deleted, ensuring these users
98 * are not reused. We don't reset the counter or random string by design.
99 *
100 * @since 1.28
101 *
102 * @param string[] $groups Groups the test user should be added to.
103 * @return TestUser
104 */
105 public static function clear() {
106 self::$testUsers = [];
107 }
108
109 /**
110 * @todo It would be nice if this were a non-static method of TestUser
111 * instead, but that doesn't seem possible without friends?
112 *
113 * @return bool True if it's safe to modify the user
114 */
115 public static function isMutable( User $user ) {
116 foreach ( self::$testUsers as $key => $testUser ) {
117 if ( $user === $testUser->getUser() ) {
118 return false;
119 }
120 }
121 return true;
122 }
123 }