MDL-52781 core_user: improve core_user::fill_properties_cache()
[moodle.git] / lib / tests / user_test.php
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/>.
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  */
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  */
32 class core_user_testcase extends advanced_testcase {
34     /**
35      * Setup test data.
36      */
37     protected function setUp() {
38         $this->resetAfterTest(true);
39     }
41     public function test_get_user() {
42         global $CFG;
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));
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);
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));
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));
73         // When supportemail is set.
74         core_user::reset_internal_users();
75         $CFG->supportemail = 'test@example.com';
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));
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     }
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();
97         // Create a default user for the test.
98         $userexpected = $this->getDataGenerator()->create_user($record);
100         // Assert that the returned user is the espected one.
101         $this->assertEquals($userexpected, core_user::get_user_by_username('johndoe'));
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'));
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));
109         // Create a new user from a different host.
110         $record['mnethostid'] = 2;
111         $userexpected2 = $this->getDataGenerator()->create_user($record);
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));
116         // Assert that a user not in the db return false.
117         $this->assertFalse(core_user::get_user_by_username('janedoe'));
118     }
120     /**
121      * Test require_active_user
122      */
123     public function test_require_active_user() {
124         global $DB;
126         // Create a default user for the test.
127         $userexpected = $this->getDataGenerator()->create_user();
129         // Simple case, all good.
130         core_user::require_active_user($userexpected, true, true);
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));
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));
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);
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         }
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         }
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         }
186     }
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);
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         }
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     }
213     /**
214      * Test validate() method.
215      */
216     public function test_validate() {
218         // Create user with just with username and firstname.
219         $record = array('username' => 's10', 'firstname' => 'Bebe Stevens');
220         $validation = core_user::validate((object)$record);
222         // Validate the user, should return true as the user data is correct.
223         $this->assertTrue($validation);
225         // Create user with incorrect data (invalid country and theme).
226         $record = array('username' => 's1', 'firstname' => 'Eric Cartman', 'country' => 'UU', 'theme' => 'beise');
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);
234         // Create user with malicious data (xss).
235         $record = array('username' => 's3', 'firstname' => 'Kyle<script>alert(1);<script> Broflovski');
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     }
243     /**
244      * Test clean_data() method.
245      */
246     public function test_clean_data() {
247         $this->resetAfterTest(false);
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);
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);
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     }
270     /**
271      * Test clean_field() method.
272      */
273     public function test_clean_field() {
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';
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'));
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     }
296     /**
297      * Test get_property_type() method.
298      */
299     public function test_get_property_type() {
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);
309         // Try to fetch type of a non-existent properties.
310         $nonexistingproperty = 'userfullname';
311         $this->setExpectedException('coding_exception', 'Invalid property requested: ' . $nonexistingproperty);
312         core_user::get_property_type($nonexistingproperty);
313         $nonexistingproperty = 'mobilenumber';
314         $this->setExpectedException('coding_exception', 'Invalid property requested: ' . $nonexistingproperty);
315         core_user::get_property_type($nonexistingproperty);
316     }
318     /**
319      * Test get_property_null() method.
320      */
321     public function test_get_property_null() {
322         // Fetch valid properties and verify if it is NULL_ALLOWED or NULL_NOT_ALLOWED.
323         $property = core_user::get_property_null('username');
324         $this->assertEquals(NULL_NOT_ALLOWED, $property);
325         $property = core_user::get_property_null('password');
326         $this->assertEquals(NULL_NOT_ALLOWED, $property);
327         $property = core_user::get_property_null('imagealt');
328         $this->assertEquals(NULL_ALLOWED, $property);
329         $property = core_user::get_property_null('middlename');
330         $this->assertEquals(NULL_ALLOWED, $property);
332         // Try to fetch type of a non-existent properties.
333         $nonexistingproperty = 'lastnamefonetic';
334         $this->setExpectedException('coding_exception', 'Invalid property requested: ' . $nonexistingproperty);
335         core_user::get_property_null($nonexistingproperty);
336         $nonexistingproperty = 'midlename';
337         $this->setExpectedException('coding_exception', 'Invalid property requested: ' . $nonexistingproperty);
338         core_user::get_property_null($nonexistingproperty);
339     }
341     /**
342      * Test get_property_choices() method.
343      */
344     public function test_get_property_choices() {
346         // Test against country property choices.
347         $choices = core_user::get_property_choices('country');
348         $this->assertArrayHasKey('AU', $choices);
349         $this->assertArrayHasKey('BR', $choices);
350         $this->assertArrayNotHasKey('WW', $choices);
351         $this->assertArrayNotHasKey('TX', $choices);
353         // Test against lang property choices.
354         $choices = core_user::get_property_choices('lang');
355         $this->assertArrayHasKey('en', $choices);
356         $this->assertArrayHasKey('ko', $choices);
357         $this->assertArrayHasKey('ru', $choices);
358         $this->assertArrayNotHasKey('ww', $choices);
359         $this->assertArrayNotHasKey('yy', $choices);
361         // Test against theme property choices.
362         $choices = core_user::get_property_choices('theme');
363         $this->assertArrayHasKey('base', $choices);
364         $this->assertArrayHasKey('clean', $choices);
365         $this->assertArrayNotHasKey('unknowntheme', $choices);
366         $this->assertArrayNotHasKey('wrongtheme', $choices);
368         // Test against timezone property choices.
369         $choices = core_user::get_property_choices('timezone');
370         $this->assertArrayHasKey('America/Sao_Paulo', $choices);
371         $this->assertArrayHasKey('Australia/Perth', $choices);
372         $this->assertArrayHasKey('99', $choices);
373         $this->assertArrayHasKey('UTC', $choices);
374         $this->assertArrayNotHasKey('North Korea', $choices);
375         $this->assertArrayNotHasKey('New york', $choices);
377         // Try to fetch type of a non-existent properties.
378         $nonexistingproperty = 'language';
379         $this->setExpectedException('coding_exception', 'Invalid property requested: ' . $nonexistingproperty);
380         core_user::get_property_null($nonexistingproperty);
381         $nonexistingproperty = 'coutries';
382         $this->setExpectedException('coding_exception', 'Invalid property requested: ' . $nonexistingproperty);
383         core_user::get_property_null($nonexistingproperty);
384     }
386     /**
387      * Test get_property_default().
388      */
389     public function test_get_property_default() {
390         global $CFG;
392         $country = core_user::get_property_default('country');
393         $this->assertEquals($CFG->country, $country);
394         set_config('country', 'AU');
395         core_user::reset_caches();
396         $country = core_user::get_property_default('country');
397         $this->assertEquals($CFG->country, $country);
399         $lang = core_user::get_property_default('lang');
400         $this->assertEquals($CFG->lang, $lang);
401         set_config('lang', 'en');
402         $lang = core_user::get_property_default('lang');
403         $this->assertEquals($CFG->lang, $lang);
405         $timezone = core_user::get_property_default('timezone');
406         $this->assertEquals($CFG->timezone, $timezone);
407         set_config('timezone', 99);
408         core_user::reset_caches();
409         $timezone = core_user::get_property_default('timezone');
410         $this->assertEquals(99, $timezone);
412         $this->setExpectedException('coding_exception', 'Invalid property requested, or the property does not has a default value.');
413         core_user::get_property_default('firstname');
414     }