2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Unit tests for user/lib.php.
22 * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
29 require_once($CFG->dirroot.'/user/lib.php');
32 * Unit tests for user lib api.
36 * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39 class core_userliblib_testcase extends advanced_testcase {
41 * Test user_update_user.
43 public function test_user_update_user() {
46 $this->resetAfterTest();
48 // Create user and modify user profile.
49 $user = $this->getDataGenerator()->create_user();
50 $user->firstname = 'Test';
51 $user->password = 'M00dLe@T';
53 // Update user and capture event.
54 $sink = $this->redirectEvents();
55 user_update_user($user);
56 $events = $sink->get_events();
58 $event = array_pop($events);
60 // Test updated value.
61 $dbuser = $DB->get_record('user', array('id' => $user->id));
62 $this->assertSame($user->firstname, $dbuser->firstname);
63 $this->assertNotSame('M00dLe@T', $dbuser->password);
66 $this->assertInstanceOf('\core\event\user_updated', $event);
67 $this->assertSame($user->id, $event->objectid);
68 $this->assertSame('user_updated', $event->get_legacy_eventname());
69 $this->assertEventLegacyData($dbuser, $event);
70 $this->assertEquals(context_user::instance($user->id), $event->get_context());
71 $expectedlogdata = array(SITEID, 'user', 'update', 'view.php?id='.$user->id, '');
72 $this->assertEventLegacyLogData($expectedlogdata, $event);
74 // Update user with no password update.
75 $password = $user->password = hash_internal_user_password('M00dLe@T');
76 user_update_user($user, false);
77 $dbuser = $DB->get_record('user', array('id' => $user->id));
78 $this->assertSame($password, $dbuser->password);
80 // Verify event is not triggred by user_update_user when needed.
81 $sink = $this->redirectEvents();
82 user_update_user($user, false, false);
83 $events = $sink->get_events();
85 $this->assertCount(0, $events);
87 // With password, there should be 1 event.
88 $sink = $this->redirectEvents();
89 user_update_user($user, true, false);
90 $events = $sink->get_events();
92 $this->assertCount(1, $events);
93 $event = array_pop($events);
94 $this->assertInstanceOf('\core\event\user_password_updated', $event);
100 public function test_create_users() {
103 $this->resetAfterTest();
106 'username' => 'usernametest1',
107 'password' => 'Moodle2012!',
108 'idnumber' => 'idnumbertest1',
109 'firstname' => 'First Name User Test 1',
110 'lastname' => 'Last Name User Test 1',
111 'middlename' => 'Middle Name User Test 1',
112 'lastnamephonetic' => '最後のお名前のテスト一号',
113 'firstnamephonetic' => 'お名前のテスト一号',
114 'alternatename' => 'Alternate Name User Test 1',
115 'email' => 'usertest1@example.com',
116 'description' => 'This is a description for user 1',
121 // Create user and capture event.
122 $sink = $this->redirectEvents();
123 $user['id'] = user_create_user($user);
124 $events = $sink->get_events();
126 $event = array_pop($events);
128 // Test user info in DB.
129 $dbuser = $DB->get_record('user', array('id' => $user['id']));
130 $this->assertEquals($dbuser->username, $user['username']);
131 $this->assertEquals($dbuser->idnumber, $user['idnumber']);
132 $this->assertEquals($dbuser->firstname, $user['firstname']);
133 $this->assertEquals($dbuser->lastname, $user['lastname']);
134 $this->assertEquals($dbuser->email, $user['email']);
135 $this->assertEquals($dbuser->description, $user['description']);
136 $this->assertEquals($dbuser->city, $user['city']);
137 $this->assertEquals($dbuser->country, $user['country']);
140 $this->assertInstanceOf('\core\event\user_created', $event);
141 $this->assertEquals($user['id'], $event->objectid);
142 $this->assertEquals('user_created', $event->get_legacy_eventname());
143 $this->assertEquals(context_user::instance($user['id']), $event->get_context());
144 $this->assertEventLegacyData($dbuser, $event);
145 $expectedlogdata = array(SITEID, 'user', 'add', '/view.php?id='.$event->objectid, fullname($dbuser));
146 $this->assertEventLegacyLogData($expectedlogdata, $event);
148 // Verify event is not triggred by user_create_user when needed.
149 $user = array('username' => 'usernametest2'); // Create another user.
150 $sink = $this->redirectEvents();
151 user_create_user($user, true, false);
152 $events = $sink->get_events();
154 $this->assertCount(0, $events);
158 * Test function user_count_login_failures().
160 public function test_user_count_login_failures() {
161 $this->resetAfterTest();
162 $user = $this->getDataGenerator()->create_user();
163 $this->assertEquals(0, get_user_preferences('login_failed_count_since_success', 0, $user));
164 for ($i = 0; $i < 10; $i++) {
165 login_attempt_failed($user);
167 $this->assertEquals(10, get_user_preferences('login_failed_count_since_success', 0, $user));
168 $count = user_count_login_failures($user); // Reset count.
169 $this->assertEquals(10, $count);
170 $this->assertEquals(0, get_user_preferences('login_failed_count_since_success', 0, $user));
172 for ($i = 0; $i < 10; $i++) {
173 login_attempt_failed($user);
175 $this->assertEquals(10, get_user_preferences('login_failed_count_since_success', 0, $user));
176 $count = user_count_login_failures($user, false); // Do not reset count.
177 $this->assertEquals(10, $count);
178 $this->assertEquals(10, get_user_preferences('login_failed_count_since_success', 0, $user));
182 * Test function user_add_password_history().
184 public function test_user_add_password_history() {
187 $this->resetAfterTest();
189 $user1 = $this->getDataGenerator()->create_user();
190 $user2 = $this->getDataGenerator()->create_user();
191 $user3 = $this->getDataGenerator()->create_user();
192 $DB->delete_records('user_password_history', array());
194 set_config('passwordreuselimit', 0);
196 user_add_password_history($user1->id, 'pokus');
197 $this->assertEquals(0, $DB->count_records('user_password_history'));
199 // Test adding and discarding of old.
201 set_config('passwordreuselimit', 3);
203 user_add_password_history($user1->id, 'pokus');
204 $this->assertEquals(1, $DB->count_records('user_password_history'));
205 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user1->id)));
207 user_add_password_history($user1->id, 'pokus2');
208 user_add_password_history($user1->id, 'pokus3');
209 user_add_password_history($user1->id, 'pokus4');
210 $this->assertEquals(3, $DB->count_records('user_password_history'));
211 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user1->id)));
213 user_add_password_history($user2->id, 'pokus1');
214 $this->assertEquals(4, $DB->count_records('user_password_history'));
215 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user1->id)));
216 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user2->id)));
218 user_add_password_history($user2->id, 'pokus2');
219 user_add_password_history($user2->id, 'pokus3');
220 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user2->id)));
222 $ids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC'));
223 user_add_password_history($user2->id, 'pokus4');
224 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user2->id)));
225 $newids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC'));
227 $removed = array_shift($ids);
228 $added = array_pop($newids);
229 $this->assertSame($ids, $newids);
230 $this->assertGreaterThan($removed, $added);
232 // Test disabling prevents changes.
234 set_config('passwordreuselimit', 0);
236 $this->assertEquals(6, $DB->count_records('user_password_history'));
238 $ids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC'));
239 user_add_password_history($user2->id, 'pokus5');
240 user_add_password_history($user3->id, 'pokus1');
241 $newids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC'));
242 $this->assertSame($ids, $newids);
243 $this->assertEquals(6, $DB->count_records('user_password_history'));
245 set_config('passwordreuselimit', -1);
247 $ids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC'));
248 user_add_password_history($user2->id, 'pokus6');
249 user_add_password_history($user3->id, 'pokus6');
250 $newids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC'));
251 $this->assertSame($ids, $newids);
252 $this->assertEquals(6, $DB->count_records('user_password_history'));
256 * Test function user_add_password_history().
258 public function test_user_is_previously_used_password() {
261 $this->resetAfterTest();
263 $user1 = $this->getDataGenerator()->create_user();
264 $user2 = $this->getDataGenerator()->create_user();
265 $DB->delete_records('user_password_history', array());
267 set_config('passwordreuselimit', 0);
269 user_add_password_history($user1->id, 'pokus');
270 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus'));
272 set_config('passwordreuselimit', 3);
274 user_add_password_history($user2->id, 'pokus1');
275 user_add_password_history($user2->id, 'pokus2');
277 user_add_password_history($user1->id, 'pokus1');
278 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus1'));
279 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus2'));
280 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus3'));
281 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus4'));
283 user_add_password_history($user1->id, 'pokus2');
284 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus1'));
285 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus2'));
286 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus3'));
287 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus4'));
289 user_add_password_history($user1->id, 'pokus3');
290 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus1'));
291 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus2'));
292 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus3'));
293 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus4'));
295 user_add_password_history($user1->id, 'pokus4');
296 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus1'));
297 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus2'));
298 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus3'));
299 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus4'));
301 set_config('passwordreuselimit', 2);
303 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus1'));
304 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus2'));
305 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus3'));
306 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus4'));
308 set_config('passwordreuselimit', 3);
310 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus1'));
311 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus2'));
312 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus3'));
313 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus4'));
315 set_config('passwordreuselimit', 0);
317 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus1'));
318 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus2'));
319 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus3'));
320 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus4'));
324 * Test that password history is deleted together with user.
326 public function test_delete_of_hashes_on_user_delete() {
329 $this->resetAfterTest();
331 $user1 = $this->getDataGenerator()->create_user();
332 $user2 = $this->getDataGenerator()->create_user();
333 $DB->delete_records('user_password_history', array());
335 set_config('passwordreuselimit', 3);
337 user_add_password_history($user1->id, 'pokus');
338 user_add_password_history($user2->id, 'pokus1');
339 user_add_password_history($user2->id, 'pokus2');
341 $this->assertEquals(3, $DB->count_records('user_password_history'));
342 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user1->id)));
343 $this->assertEquals(2, $DB->count_records('user_password_history', array('userid' => $user2->id)));
346 $this->assertEquals(1, $DB->count_records('user_password_history'));
347 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user1->id)));
348 $this->assertEquals(0, $DB->count_records('user_password_history', array('userid' => $user2->id)));
352 * Test user_list_view function
354 public function test_user_list_view() {
356 $this->resetAfterTest();
358 // Course without sections.
359 $course = $this->getDataGenerator()->create_course();
360 $context = context_course::instance($course->id);
362 $this->setAdminUser();
364 // Redirect events to the sink, so we can recover them later.
365 $sink = $this->redirectEvents();
367 user_list_view($course, $context);
368 $events = $sink->get_events();
369 $this->assertCount(1, $events);
370 $event = reset($events);
372 // Check the event details are correct.
373 $this->assertInstanceOf('\core\event\user_list_viewed', $event);
374 $this->assertEquals($context, $event->get_context());
375 $this->assertEquals($course->shortname, $event->other['courseshortname']);
376 $this->assertEquals($course->fullname, $event->other['coursefullname']);
381 * Test setting the user menu avatar size.
383 public function test_user_menu_custom_avatar_size() {
385 $this->resetAfterTest(true);
389 $user = $this->getDataGenerator()->create_user();
390 $opts = user_get_user_navigation_info($user, $PAGE, array('avatarsize' => $testsize));
391 $avatarhtml = $opts->metadata['useravatar'];
394 preg_match('/(?:.*width=")(\d*)(?:" height=")(\d*)(?:".*\/>)/', $avatarhtml, $matches);
395 $this->assertCount(3, $matches);
397 $this->assertEquals(intval($matches[1]), $testsize);
398 $this->assertEquals(intval($matches[2]), $testsize);