MDL-61028 core_form: Autocomplete field to support HTML selection
[moodle.git] / lib / tests / user_test.php
CommitLineData
3bcf6b3c
RT
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Tests core_user class.
19 *
20 * @package core
21 * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25/**
26 * Test core_user class.
27 *
28 * @package core
29 * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
30 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31 */
32class core_user_testcase extends advanced_testcase {
33
2d35b7d3
GPL
34 /**
35 * Setup test data.
36 */
37 protected function setUp() {
38 $this->resetAfterTest(true);
39 }
40
3bcf6b3c
RT
41 public function test_get_user() {
42 global $CFG;
43
3bcf6b3c
RT
44
45 // Create user and try fetach it with api.
46 $user = $this->getDataGenerator()->create_user();
47 $this->assertEquals($user, core_user::get_user($user->id, '*', MUST_EXIST));
48
49 // Test noreply user.
50 $CFG->noreplyuserid = null;
51 $noreplyuser = core_user::get_noreply_user();
52 $this->assertEquals(1, $noreplyuser->emailstop);
53 $this->assertFalse(core_user::is_real_user($noreplyuser->id));
54 $this->assertEquals($CFG->noreplyaddress, $noreplyuser->email);
55 $this->assertEquals(get_string('noreplyname'), $noreplyuser->firstname);
56
57 // Set user as noreply user and make sure noreply propery is set.
58 core_user::reset_internal_users();
59 $CFG->noreplyuserid = $user->id;
60 $noreplyuser = core_user::get_noreply_user();
61 $this->assertEquals(1, $noreplyuser->emailstop);
62 $this->assertTrue(core_user::is_real_user($noreplyuser->id));
63
64 // Test support user.
65 core_user::reset_internal_users();
66 $CFG->supportemail = null;
67 $CFG->noreplyuserid = null;
68 $supportuser = core_user::get_support_user();
69 $adminuser = get_admin();
70 $this->assertEquals($adminuser, $supportuser);
71 $this->assertTrue(core_user::is_real_user($supportuser->id));
72
73 // When supportemail is set.
74 core_user::reset_internal_users();
0fe86bbd 75 $CFG->supportemail = 'test@example.com';
3bcf6b3c
RT
76 $supportuser = core_user::get_support_user();
77 $this->assertEquals(core_user::SUPPORT_USER, $supportuser->id);
78 $this->assertFalse(core_user::is_real_user($supportuser->id));
79
80 // Set user as support user and make sure noreply propery is set.
81 core_user::reset_internal_users();
82 $CFG->supportuserid = $user->id;
83 $supportuser = core_user::get_support_user();
84 $this->assertEquals($user, $supportuser);
85 $this->assertTrue(core_user::is_real_user($supportuser->id));
86 }
2d35b7d3
GPL
87
88 /**
89 * Test get_user_by_username method.
90 */
91 public function test_get_user_by_username() {
92 $record = array();
93 $record['username'] = 'johndoe';
94 $record['email'] = 'johndoe@example.com';
95 $record['timecreated'] = time();
96
97 // Create a default user for the test.
98 $userexpected = $this->getDataGenerator()->create_user($record);
99
100 // Assert that the returned user is the espected one.
101 $this->assertEquals($userexpected, core_user::get_user_by_username('johndoe'));
102
103 // Assert that a subset of fields is correctly returned.
104 $this->assertEquals((object) $record, core_user::get_user_by_username('johndoe', 'username,email,timecreated'));
105
106 // Assert that a user with a different mnethostid will no be returned.
107 $this->assertFalse(core_user::get_user_by_username('johndoe', 'username,email,timecreated', 2));
108
109 // Create a new user from a different host.
110 $record['mnethostid'] = 2;
111 $userexpected2 = $this->getDataGenerator()->create_user($record);
112
113 // Assert that the new user is returned when specified the correct mnethostid.
114 $this->assertEquals($userexpected2, core_user::get_user_by_username('johndoe', '*', 2));
115
116 // Assert that a user not in the db return false.
117 $this->assertFalse(core_user::get_user_by_username('janedoe'));
118 }
3961ebfb
JL
119
120 /**
121 * Test require_active_user
122 */
123 public function test_require_active_user() {
124 global $DB;
125
126 // Create a default user for the test.
127 $userexpected = $this->getDataGenerator()->create_user();
128
129 // Simple case, all good.
130 core_user::require_active_user($userexpected, true, true);
131
132 // Set user not confirmed.
133 $DB->set_field('user', 'confirmed', 0, array('id' => $userexpected->id));
134 try {
135 core_user::require_active_user($userexpected);
136 } catch (moodle_exception $e) {
137 $this->assertEquals('usernotconfirmed', $e->errorcode);
138 }
139 $DB->set_field('user', 'confirmed', 1, array('id' => $userexpected->id));
140
141 // Set nologin auth method.
142 $DB->set_field('user', 'auth', 'nologin', array('id' => $userexpected->id));
143 try {
144 core_user::require_active_user($userexpected, false, true);
145 } catch (moodle_exception $e) {
146 $this->assertEquals('suspended', $e->errorcode);
147 }
148 // Check no exceptions are thrown if we don't specify to check suspended.
149 core_user::require_active_user($userexpected);
150 $DB->set_field('user', 'auth', 'manual', array('id' => $userexpected->id));
151
152 // Set user suspended.
153 $DB->set_field('user', 'suspended', 1, array('id' => $userexpected->id));
154 try {
155 core_user::require_active_user($userexpected, true);
156 } catch (moodle_exception $e) {
157 $this->assertEquals('suspended', $e->errorcode);
158 }
159 // Check no exceptions are thrown if we don't specify to check suspended.
160 core_user::require_active_user($userexpected);
161
162 // Delete user.
163 delete_user($userexpected);
164 try {
165 core_user::require_active_user($userexpected);
166 } catch (moodle_exception $e) {
167 $this->assertEquals('userdeleted', $e->errorcode);
168 }
169
170 // Use a not real user.
171 $noreplyuser = core_user::get_noreply_user();
172 try {
173 core_user::require_active_user($noreplyuser, true);
174 } catch (moodle_exception $e) {
175 $this->assertEquals('invaliduser', $e->errorcode);
176 }
177
178 // Get the guest user.
179 $guestuser = $DB->get_record('user', array('username' => 'guest'));
180 try {
181 core_user::require_active_user($guestuser, true);
182 } catch (moodle_exception $e) {
183 $this->assertEquals('guestsarenotallowed', $e->errorcode);
184 }
185
186 }
dccf9ca3
SL
187
188 /**
189 * Test get_property_definition() method.
190 */
191 public function test_get_property_definition() {
192 // Try to get a existing property.
193 $properties = core_user::get_property_definition('id');
194 $this->assertEquals($properties['type'], PARAM_INT);
195 $properties = core_user::get_property_definition('username');
196 $this->assertEquals($properties['type'], PARAM_USERNAME);
197
198 // Invalid property.
199 try {
200 core_user::get_property_definition('fullname');
201 } catch (coding_exception $e) {
202 $this->assertRegExp('/Invalid property requested./', $e->getMessage());
203 }
204
205 // Empty parameter.
206 try {
207 core_user::get_property_definition('');
208 } catch (coding_exception $e) {
209 $this->assertRegExp('/Invalid property requested./', $e->getMessage());
210 }
211 }
4ce09314
SL
212
213 /**
214 * Test validate() method.
215 */
216 public function test_validate() {
217
218 // Create user with just with username and firstname.
219 $record = array('username' => 's10', 'firstname' => 'Bebe Stevens');
220 $validation = core_user::validate((object)$record);
221
222 // Validate the user, should return true as the user data is correct.
223 $this->assertTrue($validation);
224
225 // Create user with incorrect data (invalid country and theme).
226 $record = array('username' => 's1', 'firstname' => 'Eric Cartman', 'country' => 'UU', 'theme' => 'beise');
227
228 // Should return an array with 2 errors.
229 $validation = core_user::validate((object)$record);
230 $this->assertArrayHasKey('country', $validation);
231 $this->assertArrayHasKey('theme', $validation);
232 $this->assertCount(2, $validation);
233
234 // Create user with malicious data (xss).
235 $record = array('username' => 's3', 'firstname' => 'Kyle<script>alert(1);<script> Broflovski');
236
237 // Should return an array with 1 error.
238 $validation = core_user::validate((object)$record);
239 $this->assertCount(1, $validation);
240 $this->assertArrayHasKey('firstname', $validation);
241 }
242
243 /**
244 * Test clean_data() method.
245 */
246 public function test_clean_data() {
247 $this->resetAfterTest(false);
248
249 $user = new stdClass();
250 $user->firstname = 'John <script>alert(1)</script> Doe';
251 $user->username = 'john%#&~%*_doe';
252 $user->email = ' john@testing.com ';
253 $user->deleted = 'no';
254 $user->description = '<b>A description <script>alert(123);</script>about myself.</b>';
255 $usercleaned = core_user::clean_data($user);
256
257 // Expected results.
258 $this->assertEquals('John alert(1) Doe', $usercleaned->firstname);
259 $this->assertEquals('john@testing.com', $usercleaned->email);
260 $this->assertEquals(0, $usercleaned->deleted);
261 $this->assertEquals('<b>A description <script>alert(123);</script>about myself.</b>', $user->description);
262 $this->assertEquals('john_doe', $user->username);
263
264 // Try to clean an invalid property (userfullname).
265 $user->userfullname = 'John Doe';
266 core_user::clean_data($user);
267 $this->assertDebuggingCalled("The property 'userfullname' could not be cleaned.");
268 }
269
270 /**
271 * Test clean_field() method.
272 */
273 public function test_clean_field() {
274
275 // Create a 'malicious' user object/
276 $user = new stdClass();
277 $user->firstname = 'John <script>alert(1)</script> Doe';
278 $user->username = 'john%#&~%*_doe';
279 $user->email = ' john@testing.com ';
280 $user->deleted = 'no';
281 $user->description = '<b>A description <script>alert(123);</script>about myself.</b>';
282 $user->userfullname = 'John Doe';
283
284 // Expected results.
285 $this->assertEquals('John alert(1) Doe', core_user::clean_field($user->firstname, 'firstname'));
286 $this->assertEquals('john_doe', core_user::clean_field($user->username, 'username'));
287 $this->assertEquals('john@testing.com', core_user::clean_field($user->email, 'email'));
288 $this->assertEquals(0, core_user::clean_field($user->deleted, 'deleted'));
289 $this->assertEquals('<b>A description <script>alert(123);</script>about myself.</b>', core_user::clean_field($user->description, 'description'));
290
291 // Try to clean an invalid property (fullname).
292 core_user::clean_field($user->userfullname, 'fullname');
293 $this->assertDebuggingCalled("The property 'fullname' could not be cleaned.");
294 }
295
296 /**
297 * Test get_property_type() method.
298 */
299 public function test_get_property_type() {
300
301 // Fetch valid properties and verify if the type is correct.
302 $type = core_user::get_property_type('username');
303 $this->assertEquals(PARAM_USERNAME, $type);
304 $type = core_user::get_property_type('email');
305 $this->assertEquals(PARAM_RAW_TRIMMED, $type);
306 $type = core_user::get_property_type('timezone');
307 $this->assertEquals(PARAM_TIMEZONE, $type);
308
309 // Try to fetch type of a non-existent properties.
310 $nonexistingproperty = 'userfullname';
52f3e060
RT
311 $this->expectException('coding_exception');
312 $this->expectExceptionMessage('Invalid property requested: ' . $nonexistingproperty);
4ce09314
SL
313 core_user::get_property_type($nonexistingproperty);
314 $nonexistingproperty = 'mobilenumber';
52f3e060 315 $this->expectExceptionMessage('Invalid property requested: ' . $nonexistingproperty);
4ce09314
SL
316 core_user::get_property_type($nonexistingproperty);
317 }
318
319 /**
320 * Test get_property_null() method.
321 */
322 public function test_get_property_null() {
323 // Fetch valid properties and verify if it is NULL_ALLOWED or NULL_NOT_ALLOWED.
324 $property = core_user::get_property_null('username');
325 $this->assertEquals(NULL_NOT_ALLOWED, $property);
326 $property = core_user::get_property_null('password');
327 $this->assertEquals(NULL_NOT_ALLOWED, $property);
328 $property = core_user::get_property_null('imagealt');
329 $this->assertEquals(NULL_ALLOWED, $property);
330 $property = core_user::get_property_null('middlename');
331 $this->assertEquals(NULL_ALLOWED, $property);
332
333 // Try to fetch type of a non-existent properties.
334 $nonexistingproperty = 'lastnamefonetic';
52f3e060
RT
335 $this->expectException('coding_exception');
336 $this->expectExceptionMessage('Invalid property requested: ' . $nonexistingproperty);
4ce09314
SL
337 core_user::get_property_null($nonexistingproperty);
338 $nonexistingproperty = 'midlename';
52f3e060 339 $this->expectExceptionMessage('Invalid property requested: ' . $nonexistingproperty);
4ce09314
SL
340 core_user::get_property_null($nonexistingproperty);
341 }
342
343 /**
344 * Test get_property_choices() method.
345 */
346 public function test_get_property_choices() {
347
348 // Test against country property choices.
349 $choices = core_user::get_property_choices('country');
350 $this->assertArrayHasKey('AU', $choices);
351 $this->assertArrayHasKey('BR', $choices);
352 $this->assertArrayNotHasKey('WW', $choices);
353 $this->assertArrayNotHasKey('TX', $choices);
354
355 // Test against lang property choices.
356 $choices = core_user::get_property_choices('lang');
357 $this->assertArrayHasKey('en', $choices);
4ce09314
SL
358 $this->assertArrayNotHasKey('ww', $choices);
359 $this->assertArrayNotHasKey('yy', $choices);
360
361 // Test against theme property choices.
362 $choices = core_user::get_property_choices('theme');
644fcbb6 363 $this->assertArrayHasKey('bootstrapbase', $choices);
4ce09314
SL
364 $this->assertArrayHasKey('clean', $choices);
365 $this->assertArrayNotHasKey('unknowntheme', $choices);
366 $this->assertArrayNotHasKey('wrongtheme', $choices);
367
4ce09314
SL
368 // Try to fetch type of a non-existent properties.
369 $nonexistingproperty = 'language';
52f3e060
RT
370 $this->expectException('coding_exception');
371 $this->expectExceptionMessage('Invalid property requested: ' . $nonexistingproperty);
4ce09314
SL
372 core_user::get_property_null($nonexistingproperty);
373 $nonexistingproperty = 'coutries';
52f3e060 374 $this->expectExceptionMessage('Invalid property requested: ' . $nonexistingproperty);
4ce09314
SL
375 core_user::get_property_null($nonexistingproperty);
376 }
377
378 /**
379 * Test get_property_default().
52f3e060
RT
380 *
381 *
382 * @expectedException coding_exception
383 * @expectedExceptionMessage Invalid property requested, or the property does not has a default value.
4ce09314
SL
384 */
385 public function test_get_property_default() {
386 global $CFG;
16825c4e 387 $this->resetAfterTest();
4ce09314
SL
388
389 $country = core_user::get_property_default('country');
390 $this->assertEquals($CFG->country, $country);
391 set_config('country', 'AU');
392 core_user::reset_caches();
393 $country = core_user::get_property_default('country');
394 $this->assertEquals($CFG->country, $country);
395
396 $lang = core_user::get_property_default('lang');
397 $this->assertEquals($CFG->lang, $lang);
398 set_config('lang', 'en');
399 $lang = core_user::get_property_default('lang');
400 $this->assertEquals($CFG->lang, $lang);
401
16825c4e
FM
402 $this->setTimezone('Europe/London', 'Pacific/Auckland');
403 core_user::reset_caches();
4ce09314 404 $timezone = core_user::get_property_default('timezone');
16825c4e
FM
405 $this->assertEquals('Europe/London', $timezone);
406 $this->setTimezone('99', 'Pacific/Auckland');
4ce09314
SL
407 core_user::reset_caches();
408 $timezone = core_user::get_property_default('timezone');
16825c4e 409 $this->assertEquals('Pacific/Auckland', $timezone);
4ce09314 410
4ce09314
SL
411 core_user::get_property_default('firstname');
412 }
aa03ced8
AN
413
414 /**
415 * Ensure that the noreply user is not cached.
416 */
417 public function test_get_noreply_user() {
418 global $CFG;
419
420 // Create a new fake language 'xx' with the 'noreplyname'.
421 $langfolder = $CFG->dataroot . '/lang/xx';
422 check_dir_exists($langfolder);
423 $langconfig = "<?php\n\defined('MOODLE_INTERNAL') || die();";
424 file_put_contents($langfolder . '/langconfig.php', $langconfig);
425 $langconfig = "<?php\n\$string['noreplyname'] = 'XXX';";
426 file_put_contents($langfolder . '/moodle.php', $langconfig);
427
428 $CFG->lang='en';
429 $enuser = \core_user::get_noreply_user();
430
431 $CFG->lang='xx';
432 $xxuser = \core_user::get_noreply_user();
433
434 $this->assertNotEquals($enuser, $xxuser);
435 }
436
3bcf6b3c 437}