Proyectos de Subversion Moodle

Rev

Ir a la última revisión | | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
namespace core_user;
18
 
19
/**
20
 * Unit tests for user/profile/lib.php.
21
 *
22
 * @package core_user
23
 * @copyright 2014 The Open University
24
 * @licensehttp://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25
 */
26
class profilelib_test extends \advanced_testcase {
27
 
28
    /**
29
     * Load required test libraries
30
     */
31
    public static function setUpBeforeClass(): void {
32
        global $CFG;
33
        require_once("{$CFG->dirroot}/user/profile/lib.php");
34
    }
35
 
36
    /**
37
     * Tests profile_get_custom_fields function and checks it is consistent
38
     * with profile_user_record.
39
     */
40
    public function test_get_custom_fields() {
41
        $this->resetAfterTest();
42
        $user = $this->getDataGenerator()->create_user();
43
 
44
        // Add a custom field of textarea type.
45
        $id1 = $this->getDataGenerator()->create_custom_profile_field([
46
                'shortname' => 'frogdesc', 'name' => 'Description of frog',
47
                'datatype' => 'textarea'])->id;
48
 
49
        // Check the field is returned.
50
        $result = profile_get_custom_fields();
51
        $this->assertArrayHasKey($id1, $result);
52
        $this->assertEquals('frogdesc', $result[$id1]->shortname);
53
 
54
        // Textarea types are not included in user data though, so if we
55
        // use the 'only in user data' parameter, there is still nothing.
56
        $this->assertArrayNotHasKey($id1, profile_get_custom_fields(true));
57
 
58
        // Check that profile_user_record returns same (no) fields.
59
        $this->assertObjectNotHasProperty('frogdesc', profile_user_record($user->id));
60
 
61
        // Check that profile_user_record returns all the fields when requested.
62
        $this->assertObjectHasProperty('frogdesc', profile_user_record($user->id, false));
63
 
64
        // Add another custom field, this time of normal text type.
65
        $id2 = $this->getDataGenerator()->create_custom_profile_field(array(
66
                'shortname' => 'frogname', 'name' => 'Name of frog',
67
                'datatype' => 'text'))->id;
68
 
69
        // Check both are returned using normal option.
70
        $result = profile_get_custom_fields();
71
        $this->assertArrayHasKey($id2, $result);
72
        $this->assertEquals('frogname', $result[$id2]->shortname);
73
 
74
        // And check that only the one is returned the other way.
75
        $this->assertArrayHasKey($id2, profile_get_custom_fields(true));
76
 
77
        // Check profile_user_record returns same field.
78
        $this->assertObjectHasProperty('frogname', profile_user_record($user->id));
79
 
80
        // Check that profile_user_record returns all the fields when requested.
81
        $this->assertObjectHasProperty('frogname', profile_user_record($user->id, false));
82
    }
83
 
84
    /**
85
     * Make sure that all profile fields can be initialised without arguments.
86
     */
87
    public function test_default_constructor() {
88
        global $DB, $CFG;
89
        require_once($CFG->dirroot . '/user/profile/definelib.php');
90
        $datatypes = profile_list_datatypes();
91
        foreach ($datatypes as $datatype => $datatypename) {
92
            require_once($CFG->dirroot . '/user/profile/field/' .
93
                $datatype . '/field.class.php');
94
            $newfield = 'profile_field_' . $datatype;
95
            $formfield = new $newfield();
96
            $this->assertNotNull($formfield);
97
        }
98
    }
99
 
100
    /**
101
     * Test profile_view function
102
     */
103
    public function test_profile_view() {
104
        global $USER;
105
 
106
        $this->resetAfterTest();
107
 
108
        // Course without sections.
109
        $course = $this->getDataGenerator()->create_course();
110
        $context = \context_course::instance($course->id);
111
        $user = $this->getDataGenerator()->create_user();
112
        $usercontext = \context_user::instance($user->id);
113
 
114
        $this->setUser($user);
115
 
116
        // Redirect events to the sink, so we can recover them later.
117
        $sink = $this->redirectEvents();
118
 
119
        profile_view($user, $context, $course);
120
        $events = $sink->get_events();
121
        $event = reset($events);
122
 
123
        // Check the event details are correct.
124
        $this->assertInstanceOf('\core\event\user_profile_viewed', $event);
125
        $this->assertEquals($context, $event->get_context());
126
        $this->assertEquals($user->id, $event->relateduserid);
127
        $this->assertEquals($course->id, $event->other['courseid']);
128
        $this->assertEquals($course->shortname, $event->other['courseshortname']);
129
        $this->assertEquals($course->fullname, $event->other['coursefullname']);
130
 
131
        profile_view($user, $usercontext);
132
        $events = $sink->get_events();
133
        $event = array_pop($events);
134
        $sink->close();
135
 
136
        $this->assertInstanceOf('\core\event\user_profile_viewed', $event);
137
        $this->assertEquals($usercontext, $event->get_context());
138
        $this->assertEquals($user->id, $event->relateduserid);
139
 
140
    }
141
 
142
    /**
143
     * Test that {@link user_not_fully_set_up()} takes required custom fields into account.
144
     */
145
    public function test_profile_has_required_custom_fields_set() {
146
        global $CFG;
147
        require_once($CFG->dirroot.'/mnet/lib.php');
148
 
149
        $this->resetAfterTest();
150
 
151
        // Add a required, visible, unlocked custom field.
152
        $this->getDataGenerator()->create_custom_profile_field(['shortname' => 'house', 'name' => 'House', 'required' => 1,
153
            'visible' => 1, 'locked' => 0, 'datatype' => 'text']);
154
 
155
        // Add an optional, visible, unlocked custom field.
156
        $this->getDataGenerator()->create_custom_profile_field(['shortname' => 'pet', 'name' => 'Pet', 'required' => 0,
157
            'visible' => 1, 'locked' => 0, 'datatype' => 'text']);
158
 
159
        // Add required but invisible custom field.
160
        $this->getDataGenerator()->create_custom_profile_field(['shortname' => 'secretid', 'name' => 'Secret ID',
161
            'required' => 1, 'visible' => 0, 'locked' => 0, 'datatype' => 'text']);
162
 
163
        // Add required but locked custom field.
164
        $this->getDataGenerator()->create_custom_profile_field(['shortname' => 'muggleborn', 'name' => 'Muggle-born',
165
            'required' => 1, 'visible' => 1, 'locked' => 1, 'datatype' => 'checkbox']);
166
 
167
        // Create some student accounts.
168
        $hermione = $this->getDataGenerator()->create_user();
169
        $harry = $this->getDataGenerator()->create_user();
170
        $ron = $this->getDataGenerator()->create_user();
171
        $draco = $this->getDataGenerator()->create_user();
172
 
173
        // Hermione has all available custom fields filled (of course she has).
174
        profile_save_data((object)['id' => $hermione->id, 'profile_field_house' => 'Gryffindor']);
175
        profile_save_data((object)['id' => $hermione->id, 'profile_field_pet' => 'Crookshanks']);
176
 
177
        // Harry has only the optional field filled.
178
        profile_save_data((object)['id' => $harry->id, 'profile_field_pet' => 'Hedwig']);
179
 
180
        // Draco has only the required field filled.
181
        profile_save_data((object)['id' => $draco->id, 'profile_field_house' => 'Slytherin']);
182
 
183
        // Only students with required fields filled should be considered as fully set up in the default (strict) mode.
184
        $this->assertFalse(user_not_fully_set_up($hermione));
185
        $this->assertFalse(user_not_fully_set_up($draco));
186
        $this->assertTrue(user_not_fully_set_up($harry));
187
        $this->assertTrue(user_not_fully_set_up($ron));
188
 
189
        // In the lax mode, students do not need to have required fields filled.
190
        $this->assertFalse(user_not_fully_set_up($hermione, false));
191
        $this->assertFalse(user_not_fully_set_up($draco, false));
192
        $this->assertFalse(user_not_fully_set_up($harry, false));
193
        $this->assertFalse(user_not_fully_set_up($ron, false));
194
 
195
        // Lack of required core field is seen as a problem in either mode.
196
        unset($hermione->email);
197
        $this->assertTrue(user_not_fully_set_up($hermione, true));
198
        $this->assertTrue(user_not_fully_set_up($hermione, false));
199
 
200
        // When confirming remote MNet users, we do not have custom fields available.
201
        $roamingharry = mnet_strip_user($harry, ['firstname', 'lastname', 'email']);
202
        $roaminghermione = mnet_strip_user($hermione, ['firstname', 'lastname', 'email']);
203
 
204
        $this->assertTrue(user_not_fully_set_up($roamingharry, true));
205
        $this->assertFalse(user_not_fully_set_up($roamingharry, false));
206
        $this->assertTrue(user_not_fully_set_up($roaminghermione, true));
207
        $this->assertTrue(user_not_fully_set_up($roaminghermione, false));
208
    }
209
 
210
    /**
211
     * Test that user generator sets the custom profile fields
212
     */
213
    public function test_profile_fields_in_generator() {
214
        global $CFG;
215
        require_once($CFG->dirroot.'/mnet/lib.php');
216
 
217
        $this->resetAfterTest();
218
 
219
        // Add a required, visible, unlocked custom field.
220
        $this->getDataGenerator()->create_custom_profile_field(['shortname' => 'house', 'name' => 'House', 'required' => 1,
221
            'visible' => 1, 'locked' => 0, 'datatype' => 'text', 'defaultdata' => null]);
222
 
223
        // Create some student accounts.
224
        $hermione = $this->getDataGenerator()->create_user(['profile_field_house' => 'Gryffindor']);
225
        $harry = $this->getDataGenerator()->create_user();
226
 
227
        // Only students with required fields filled should be considered as fully set up.
228
        $this->assertFalse(user_not_fully_set_up($hermione));
229
        $this->assertTrue(user_not_fully_set_up($harry));
230
 
231
        // Test that the profile fields were actually set.
232
        $profilefields1 = profile_user_record($hermione->id);
233
        $this->assertEquals('Gryffindor', $profilefields1->house);
234
 
235
        $profilefields2 = profile_user_record($harry->id);
236
        $this->assertObjectHasProperty('house', $profilefields2);
237
        $this->assertNull($profilefields2->house);
238
    }
239
 
240
    /**
241
     * Tests the profile_get_custom_field_data_by_shortname function when working normally.
242
     */
243
    public function test_profile_get_custom_field_data_by_shortname_normal() {
244
        global $DB;
245
 
246
        $this->resetAfterTest();
247
 
248
        // Create 3 profile fields.
249
        $generator = $this->getDataGenerator();
250
        $field1 = $generator->create_custom_profile_field(['datatype' => 'text',
251
                'shortname' => 'speciality', 'name' => 'Speciality',
252
                'visible' => PROFILE_VISIBLE_ALL]);
253
        $field2 = $generator->create_custom_profile_field(['datatype' => 'menu',
254
                'shortname' => 'veggie', 'name' => 'Vegetarian',
255
                'visible' => PROFILE_VISIBLE_PRIVATE]);
256
 
257
        // Get the first field data and check it is correct.
258
        $data = profile_get_custom_field_data_by_shortname('speciality');
259
        $this->assertEquals('Speciality', $data->name);
260
        $this->assertEquals(PROFILE_VISIBLE_ALL, $data->visible);
261
        $this->assertEquals($field1->id, $data->id);
262
 
263
        // Get the second field data, checking there is no database query this time.
264
        $before = $DB->perf_get_queries();
265
        $data = profile_get_custom_field_data_by_shortname('veggie');
266
        $this->assertEquals($before, $DB->perf_get_queries());
267
        $this->assertEquals('Vegetarian', $data->name);
268
        $this->assertEquals(PROFILE_VISIBLE_PRIVATE, $data->visible);
269
        $this->assertEquals($field2->id, $data->id);
270
    }
271
 
272
    /**
273
     * Tests the profile_get_custom_field_data_by_shortname function with a field that doesn't exist.
274
     */
275
    public function test_profile_get_custom_field_data_by_shortname_missing() {
276
        $this->assertNull(profile_get_custom_field_data_by_shortname('speciality'));
277
    }
278
 
279
    /**
280
     * Data provider for {@see test_profile_get_custom_field_data_by_shortname_case_sensitivity}
281
     *
282
     * @return array[]
283
     */
284
    public function profile_get_custom_field_data_by_shortname_case_sensitivity_provider(): array {
285
        return [
286
            'Matching case, case-sensitive search' => ['hello', 'hello', true, true],
287
            'Matching case, case-insensitive search' => ['hello', 'hello', false, true],
288
            'Non-matching case, case-sensitive search' => ['hello', 'Hello', true, false],
289
            'Non-matching case, case-insensitive search' => ['hello', 'Hello', false, true],
290
            'Non-matching, case-sensitive search' => ['hello', 'hola', true, false],
291
            'Non-matching, case-insensitive search' => ['hello', 'hola', false, false],
292
        ];
293
    }
294
 
295
    /**
296
     * Test retrieving custom field by shortname, specifying case-sensitivity when matching
297
     *
298
     * @param string $shortname
299
     * @param string $shortnamesearch
300
     * @param bool $casesensitive
301
     * @param bool $expectmatch
302
     *
303
     * @dataProvider profile_get_custom_field_data_by_shortname_case_sensitivity_provider
304
     */
305
    public function test_profile_get_custom_field_data_by_shortname_case_sensitivity(
306
        string $shortname,
307
        string $shortnamesearch,
308
        bool $casesensitive,
309
        bool $expectmatch
310
    ): void {
311
        $this->resetAfterTest();
312
 
313
        $this->getDataGenerator()->create_custom_profile_field([
314
            'datatype' => 'text',
315
            'shortname' => $shortname,
316
            'name' => 'My field',
317
        ]);
318
 
319
        $customfield = profile_get_custom_field_data_by_shortname($shortnamesearch, $casesensitive);
320
        if ($expectmatch) {
321
            $this->assertInstanceOf(\stdClass::class, $customfield);
322
            $this->assertEquals('text', $customfield->datatype);
323
            $this->assertEquals($shortname, $customfield->shortname);
324
            $this->assertEquals('My field', $customfield->name);
325
        } else {
326
            $this->assertNull($customfield);
327
        }
328
    }
329
 
330
    /**
331
     * Test profile field loading via profile_get_user_field helper
332
     *
333
     * @covers ::profile_get_user_field
334
     */
335
    public function test_profile_get_user_field(): void {
336
        $this->resetAfterTest();
337
 
338
        $profilefield = $this->getDataGenerator()->create_custom_profile_field([
339
            'shortname' => 'fruit',
340
            'name' => 'Fruit',
341
            'datatype' => 'text',
342
        ]);
343
        $user = $this->getDataGenerator()->create_user(['profile_field_fruit' => 'Apple']);
344
 
345
        $fieldinstance = profile_get_user_field('text', $profilefield->id, $user->id);
346
        $this->assertInstanceOf(\profile_field_text::class, $fieldinstance);
347
        $this->assertEquals($profilefield->id, $fieldinstance->fieldid);
348
        $this->assertEquals($user->id, $fieldinstance->userid);
349
        $this->assertEquals('Apple', $fieldinstance->data);
350
    }
351
}