Merge branch 'MDL-47463-master' of git://github.com/FMCorz/moodle
[moodle.git] / lib / testing / generator / data_generator.php
CommitLineData
7e7cfe7a
PS
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 * Data generator.
19 *
20 * @package core
6b219869 21 * @category test
7e7cfe7a
PS
22 * @copyright 2012 Petr Skoda {@link http://skodak.org}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
c29e3e24 26defined('MOODLE_INTERNAL') || die();
7e7cfe7a
PS
27
28/**
6b219869 29 * Data generator class for unit tests and other tools that need to create fake test sites.
7e7cfe7a
PS
30 *
31 * @package core
6b219869 32 * @category test
7e7cfe7a
PS
33 * @copyright 2012 Petr Skoda {@link http://skodak.org}
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 */
5c3c2c81 36class testing_data_generator {
15ace204 37 protected $gradecategorycounter = 0;
7e7cfe7a
PS
38 protected $usercounter = 0;
39 protected $categorycount = 0;
4729332b 40 protected $cohortcount = 0;
7e7cfe7a
PS
41 protected $coursecount = 0;
42 protected $scalecount = 0;
43 protected $groupcount = 0;
44 protected $groupingcount = 0;
702851c0 45 protected $rolecount = 0;
e0c86198 46 protected $tagcount = 0;
7e7cfe7a
PS
47
48 /** @var array list of plugin generators */
49 protected $generators = array();
50
51 /** @var array lis of common last names */
52 public $lastnames = array(
53 'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Miller', 'Davis', 'García', 'Rodríguez', 'Wilson',
54 'Müller', 'Schmidt', 'Schneider', 'Fischer', 'Meyer', 'Weber', 'Schulz', 'Wagner', 'Becker', 'Hoffmann',
55 'Novák', 'Svoboda', 'Novotný', 'Dvořák', 'Černý', 'Procházková', 'Kučerová', 'Veselá', 'Horáková', 'Němcová',
56 'Смирнов', 'Иванов', 'Кузнецов', 'Соколов', 'Попов', 'Лебедева', 'Козлова', 'Новикова', 'Морозова', 'Петрова',
57 '王', '李', '张', '刘', '陈', '楊', '黃', '趙', '吳', '周',
58 '佐藤', '鈴木', '高橋', '田中', '渡辺', '伊藤', '山本', '中村', '小林', '斎藤',
59 );
60
61 /** @var array lis of common first names */
62 public $firstnames = array(
63 'Jacob', 'Ethan', 'Michael', 'Jayden', 'William', 'Isabella', 'Sophia', 'Emma', 'Olivia', 'Ava',
64 'Lukas', 'Leon', 'Luca', 'Timm', 'Paul', 'Leonie', 'Leah', 'Lena', 'Hanna', 'Laura',
65 'Jakub', 'Jan', 'Tomáš', 'Lukáš', 'Matěj', 'Tereza', 'Eliška', 'Anna', 'Adéla', 'Karolína',
66 'Даниил', 'Максим', 'Артем', 'Иван', 'Александр', 'София', 'Анастасия', 'Дарья', 'Мария', 'Полина',
67 '伟', '伟', '芳', '伟', '秀英', '秀英', '娜', '秀英', '伟', '敏',
68 '翔', '大翔', '拓海', '翔太', '颯太', '陽菜', 'さくら', '美咲', '葵', '美羽',
69 );
70
71 public $loremipsum = <<<EOD
72Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla non arcu lacinia neque faucibus fringilla. Vivamus porttitor turpis ac leo. Integer in sapien. Nullam eget nisl. Aliquam erat volutpat. Cras elementum. Mauris suscipit, ligula sit amet pharetra semper, nibh ante cursus purus, vel sagittis velit mauris vel metus. Integer malesuada. Nullam lectus justo, vulputate eget mollis sed, tempor sed magna. Mauris elementum mauris vitae tortor. Aliquam erat volutpat.
73Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Pellentesque ipsum. Cras pede libero, dapibus nec, pretium sit amet, tempor quis. Aliquam ante. Proin in tellus sit amet nibh dignissim sagittis. Vivamus porttitor turpis ac leo. Duis bibendum, lectus ut viverra rhoncus, dolor nunc faucibus libero, eget facilisis enim ipsum id lacus. In sem justo, commodo ut, suscipit at, pharetra vitae, orci. Aliquam erat volutpat. Nulla est.
74Vivamus luctus egestas leo. Aenean fermentum risus id tortor. Mauris dictum facilisis augue. Aliquam erat volutpat. Aliquam ornare wisi eu metus. Aliquam id dolor. Duis condimentum augue id magna semper rutrum. Donec iaculis gravida nulla. Pellentesque ipsum. Etiam dictum tincidunt diam. Quisque tincidunt scelerisque libero. Etiam egestas wisi a erat.
75Integer lacinia. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris tincidunt sem sed arcu. Nullam feugiat, turpis at pulvinar vulputate, erat libero tristique tellus, nec bibendum odio risus sit amet ante. Aliquam id dolor. Maecenas sollicitudin. Et harum quidem rerum facilis est et expedita distinctio. Mauris suscipit, ligula sit amet pharetra semper, nibh ante cursus purus, vel sagittis velit mauris vel metus. Nullam dapibus fermentum ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Pellentesque sapien. Duis risus. Mauris elementum mauris vitae tortor. Suspendisse nisl. Integer rutrum, orci vestibulum ullamcorper ultricies, lacus quam ultricies odio, vitae placerat pede sem sit amet enim.
76In laoreet, magna id viverra tincidunt, sem odio bibendum justo, vel imperdiet sapien wisi sed libero. Proin pede metus, vulputate nec, fermentum fringilla, vehicula vitae, justo. Nullam justo enim, consectetuer nec, ullamcorper ac, vestibulum in, elit. Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? Maecenas lorem. Etiam posuere lacus quis dolor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Curabitur ligula sapien, pulvinar a vestibulum quis, facilisis vel sapien. Nam sed tellus id magna elementum tincidunt. Suspendisse nisl. Vivamus luctus egestas leo. Nulla non arcu lacinia neque faucibus fringilla. Etiam dui sem, fermentum vitae, sagittis id, malesuada in, quam. Etiam dictum tincidunt diam. Etiam commodo dui eget wisi. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Proin pede metus, vulputate nec, fermentum fringilla, vehicula vitae, justo. Duis ante orci, molestie vitae vehicula venenatis, tincidunt ac pede. Pellentesque sapien.
77EOD;
78
79 /**
80 * To be called from data reset code only,
81 * do not use in tests.
82 * @return void
83 */
84 public function reset() {
85 $this->usercounter = 0;
86 $this->categorycount = 0;
87 $this->coursecount = 0;
88 $this->scalecount = 0;
89
5c3c2c81 90 foreach ($this->generators as $generator) {
7e7cfe7a
PS
91 $generator->reset();
92 }
93 }
94
95 /**
ba203de1
TH
96 * Return generator for given plugin or component.
97 * @param string $component the component name, e.g. 'mod_forum' or 'core_question'.
98 * @return component_generator_base or rather an instance of the appropriate subclass.
7e7cfe7a
PS
99 */
100 public function get_plugin_generator($component) {
56da374e 101 list($type, $plugin) = core_component::normalize_component($component);
ba203de1
TH
102 $cleancomponent = $type . '_' . $plugin;
103 if ($cleancomponent != $component) {
104 debugging("Please specify the component you want a generator for as " .
105 "{$cleancomponent}, not {$component}.", DEBUG_DEVELOPER);
106 $component = $cleancomponent;
107 }
7e7cfe7a 108
ba203de1
TH
109 if (isset($this->generators[$component])) {
110 return $this->generators[$component];
7e7cfe7a
PS
111 }
112
b0d1d941 113 $dir = core_component::get_component_directory($component);
ba203de1
TH
114 $lib = $dir . '/tests/generator/lib.php';
115 if (!$dir || !is_readable($lib)) {
116 throw new coding_exception("Component {$component} does not support " .
117 "generators yet. Missing tests/generator/lib.php.");
118 }
7e7cfe7a 119
ba203de1
TH
120 include_once($lib);
121 $classname = $component . '_generator';
122
123 if (!class_exists($classname)) {
124 throw new coding_exception("Component {$component} does not support " .
125 "data generators yet. Class {$classname} not found.");
7e7cfe7a
PS
126 }
127
ba203de1
TH
128 $this->generators[$component] = new $classname($this);
129 return $this->generators[$component];
7e7cfe7a
PS
130 }
131
132 /**
133 * Create a test user
134 * @param array|stdClass $record
135 * @param array $options
136 * @return stdClass user record
137 */
138 public function create_user($record=null, array $options=null) {
139 global $DB, $CFG;
140
141 $this->usercounter++;
142 $i = $this->usercounter;
143
144 $record = (array)$record;
145
146 if (!isset($record['auth'])) {
147 $record['auth'] = 'manual';
148 }
149
150 if (!isset($record['firstname']) and !isset($record['lastname'])) {
151 $country = rand(0, 5);
152 $firstname = rand(0, 4);
153 $lastname = rand(0, 4);
154 $female = rand(0, 1);
155 $record['firstname'] = $this->firstnames[($country*10) + $firstname + ($female*5)];
156 $record['lastname'] = $this->lastnames[($country*10) + $lastname + ($female*5)];
157
158 } else if (!isset($record['firstname'])) {
159 $record['firstname'] = 'Firstname'.$i;
160
161 } else if (!isset($record['lastname'])) {
162 $record['lastname'] = 'Lastname'.$i;
163 }
164
a327f25e
AG
165 if (!isset($record['firstnamephonetic'])) {
166 $firstnamephonetic = rand(0, 59);
167 $record['firstnamephonetic'] = $this->firstnames[$firstnamephonetic];
168 }
169
170 if (!isset($record['lasttnamephonetic'])) {
171 $lastnamephonetic = rand(0, 59);
172 $record['lastnamephonetic'] = $this->lastnames[$lastnamephonetic];
173 }
174
175 if (!isset($record['middlename'])) {
176 $middlename = rand(0, 59);
177 $record['middlename'] = $this->firstnames[$middlename];
178 }
179
180 if (!isset($record['alternatename'])) {
181 $alternatename = rand(0, 59);
182 $record['alternatename'] = $this->firstnames[$alternatename];
183 }
184
7e7cfe7a
PS
185 if (!isset($record['idnumber'])) {
186 $record['idnumber'] = '';
187 }
188
189 if (!isset($record['mnethostid'])) {
190 $record['mnethostid'] = $CFG->mnet_localhost_id;
191 }
192
193 if (!isset($record['username'])) {
fe67134e
PS
194 $record['username'] = 'username'.$i;
195 $j = 2;
7e7cfe7a 196 while ($DB->record_exists('user', array('username'=>$record['username'], 'mnethostid'=>$record['mnethostid']))) {
fe67134e
PS
197 $record['username'] = 'username'.$i.'_'.$j;
198 $j++;
7e7cfe7a
PS
199 }
200 }
201
dbf60a04
PS
202 if (isset($record['password'])) {
203 $record['password'] = hash_internal_user_password($record['password']);
204 } else {
205 // The auth plugin may not fully support this,
206 // but it is still better/faster than hashing random stuff.
207 $record['password'] = AUTH_PASSWORD_NOT_CACHED;
7e7cfe7a
PS
208 }
209
210 if (!isset($record['email'])) {
211 $record['email'] = $record['username'].'@example.com';
212 }
213
214 if (!isset($record['confirmed'])) {
215 $record['confirmed'] = 1;
216 }
217
218 if (!isset($record['lang'])) {
219 $record['lang'] = 'en';
220 }
221
222 if (!isset($record['maildisplay'])) {
9f7379e9
MG
223 $record['maildisplay'] = $CFG->defaultpreference_maildisplay;
224 }
225
226 if (!isset($record['mailformat'])) {
227 $record['mailformat'] = $CFG->defaultpreference_mailformat;
228 }
229
230 if (!isset($record['maildigest'])) {
231 $record['maildigest'] = $CFG->defaultpreference_maildigest;
232 }
233
234 if (!isset($record['autosubscribe'])) {
235 $record['autosubscribe'] = $CFG->defaultpreference_autosubscribe;
236 }
237
238 if (!isset($record['trackforums'])) {
239 $record['trackforums'] = $CFG->defaultpreference_trackforums;
7e7cfe7a
PS
240 }
241
242 if (!isset($record['deleted'])) {
243 $record['deleted'] = 0;
244 }
245
2d35b7d3
GPL
246 if (!isset($record['timecreated'])) {
247 $record['timecreated'] = time();
248 }
249
7e7cfe7a
PS
250 $record['timemodified'] = $record['timecreated'];
251 $record['lastip'] = '0.0.0.0';
252
7e7cfe7a
PS
253 if ($record['deleted']) {
254 $delname = $record['email'].'.'.time();
255 while ($DB->record_exists('user', array('username'=>$delname))) {
256 $delname++;
257 }
258 $record['idnumber'] = '';
259 $record['email'] = md5($record['username']);
260 $record['username'] = $delname;
261 $record['picture'] = 0;
262 }
263
264 $userid = $DB->insert_record('user', $record);
265
266 if (!$record['deleted']) {
267 context_user::instance($userid);
268 }
269
270 return $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
271 }
272
273 /**
274 * Create a test course category
275 * @param array|stdClass $record
276 * @param array $options
b28bb7e8 277 * @return coursecat course category record
7e7cfe7a 278 */
4729332b 279 public function create_category($record=null, array $options=null) {
7e7cfe7a 280 global $DB, $CFG;
b28bb7e8 281 require_once("$CFG->libdir/coursecatlib.php");
7e7cfe7a
PS
282
283 $this->categorycount++;
284 $i = $this->categorycount;
285
286 $record = (array)$record;
287
288 if (!isset($record['name'])) {
289 $record['name'] = 'Course category '.$i;
290 }
291
7e7cfe7a
PS
292 if (!isset($record['description'])) {
293 $record['description'] = "Test course category $i\n$this->loremipsum";
294 }
295
b28bb7e8
MG
296 if (!isset($record['idnumber'])) {
297 $record['idnumber'] = '';
7e7cfe7a 298 }
7e7cfe7a 299
b28bb7e8 300 return coursecat::create($record);
7e7cfe7a
PS
301 }
302
4729332b
PS
303 /**
304 * Create test cohort.
305 * @param array|stdClass $record
306 * @param array $options
307 * @return stdClass cohort record
308 */
309 public function create_cohort($record=null, array $options=null) {
310 global $DB, $CFG;
311 require_once("$CFG->dirroot/cohort/lib.php");
312
313 $this->cohortcount++;
314 $i = $this->cohortcount;
315
316 $record = (array)$record;
317
318 if (!isset($record['contextid'])) {
319 $record['contextid'] = context_system::instance()->id;
320 }
321
322 if (!isset($record['name'])) {
323 $record['name'] = 'Cohort '.$i;
324 }
325
326 if (!isset($record['idnumber'])) {
327 $record['idnumber'] = '';
328 }
329
330 if (!isset($record['description'])) {
331 $record['description'] = "Test cohort $i\n$this->loremipsum";
332 }
333
334 if (!isset($record['descriptionformat'])) {
335 $record['descriptionformat'] = FORMAT_MOODLE;
336 }
337
80f98467
MG
338 if (!isset($record['visible'])) {
339 $record['visible'] = 1;
340 }
341
4729332b
PS
342 if (!isset($record['component'])) {
343 $record['component'] = '';
344 }
345
346 $id = cohort_add_cohort((object)$record);
347
348 return $DB->get_record('cohort', array('id'=>$id), '*', MUST_EXIST);
349 }
350
7e7cfe7a
PS
351 /**
352 * Create a test course
353 * @param array|stdClass $record
354 * @param array $options with keys:
355 * 'createsections'=>bool precreate all sections
356 * @return stdClass course record
357 */
4729332b 358 public function create_course($record=null, array $options=null) {
7e7cfe7a
PS
359 global $DB, $CFG;
360 require_once("$CFG->dirroot/course/lib.php");
361
362 $this->coursecount++;
363 $i = $this->coursecount;
364
365 $record = (array)$record;
366
367 if (!isset($record['fullname'])) {
368 $record['fullname'] = 'Test course '.$i;
369 }
370
371 if (!isset($record['shortname'])) {
372 $record['shortname'] = 'tc_'.$i;
373 }
374
375 if (!isset($record['idnumber'])) {
376 $record['idnumber'] = '';
377 }
378
379 if (!isset($record['format'])) {
380 $record['format'] = 'topics';
381 }
382
383 if (!isset($record['newsitems'])) {
384 $record['newsitems'] = 0;
385 }
386
387 if (!isset($record['numsections'])) {
388 $record['numsections'] = 5;
389 }
390
4a38e659
PS
391 if (!isset($record['summary'])) {
392 $record['summary'] = "Test course $i\n$this->loremipsum";
7e7cfe7a
PS
393 }
394
4a38e659
PS
395 if (!isset($record['summaryformat'])) {
396 $record['summaryformat'] = FORMAT_MOODLE;
7e7cfe7a
PS
397 }
398
399 if (!isset($record['category'])) {
400 $record['category'] = $DB->get_field_select('course_categories', "MIN(id)", "parent=0");
401 }
402
403 $course = create_course((object)$record);
404 context_course::instance($course->id);
7e7cfe7a 405 if (!empty($options['createsections'])) {
384c3510
MG
406 if (isset($course->numsections)) {
407 course_create_sections_if_missing($course, range(0, $course->numsections));
408 } else {
409 course_create_sections_if_missing($course, 0);
7e7cfe7a
PS
410 }
411 }
412
413 return $course;
414 }
415
416 /**
417 * Create course section if does not exist yet
384c3510 418 * @param array|stdClass $record must contain 'course' and 'section' attributes
7e7cfe7a
PS
419 * @param array|null $options
420 * @return stdClass
421 * @throws coding_exception
422 */
423 public function create_course_section($record = null, array $options = null) {
424 global $DB;
425
426 $record = (array)$record;
427
428 if (empty($record['course'])) {
5c3c2c81 429 throw new coding_exception('course must be present in testing_data_generator::create_course_section() $record');
7e7cfe7a
PS
430 }
431
432 if (!isset($record['section'])) {
5c3c2c81 433 throw new coding_exception('section must be present in testing_data_generator::create_course_section() $record');
7e7cfe7a
PS
434 }
435
b46be6ad
MG
436 course_create_sections_if_missing($record['course'], $record['section']);
437 return get_fast_modinfo($record['course'])->get_section_info($record['section']);
7e7cfe7a
PS
438 }
439
440 /**
441 * Create a test block
442 * @param string $blockname
443 * @param array|stdClass $record
444 * @param array $options
445 * @return stdClass block instance record
446 */
447 public function create_block($blockname, $record=null, array $options=null) {
448 $generator = $this->get_plugin_generator('block_'.$blockname);
449 return $generator->create_instance($record, $options);
450 }
451
452 /**
453 * Create a test module
454 * @param string $modulename
455 * @param array|stdClass $record
456 * @param array $options
457 * @return stdClass activity record
458 */
459 public function create_module($modulename, $record=null, array $options=null) {
460 $generator = $this->get_plugin_generator('mod_'.$modulename);
461 return $generator->create_instance($record, $options);
462 }
463
464 /**
465 * Create a test group for the specified course
466 *
467 * $record should be either an array or a stdClass containing infomation about the group to create.
468 * At the very least it needs to contain courseid.
469 * Default values are added for name, description, and descriptionformat if they are not present.
470 *
6b219869
DM
471 * This function calls groups_create_group() to create the group within the database.
472 * @see groups_create_group
7e7cfe7a
PS
473 * @param array|stdClass $record
474 * @return stdClass group record
475 */
476 public function create_group($record) {
477 global $DB, $CFG;
478
479 require_once($CFG->dirroot . '/group/lib.php');
480
481 $this->groupcount++;
482 $i = $this->groupcount;
483
484 $record = (array)$record;
485
486 if (empty($record['courseid'])) {
5c3c2c81 487 throw new coding_exception('courseid must be present in testing_data_generator::create_group() $record');
7e7cfe7a
PS
488 }
489
490 if (!isset($record['name'])) {
491 $record['name'] = 'group-' . $i;
492 }
493
494 if (!isset($record['description'])) {
495 $record['description'] = "Test Group $i\n{$this->loremipsum}";
496 }
497
498 if (!isset($record['descriptionformat'])) {
499 $record['descriptionformat'] = FORMAT_MOODLE;
500 }
501
502 $id = groups_create_group((object)$record);
503
504 return $DB->get_record('groups', array('id'=>$id));
505 }
506
87bb583c
DM
507 /**
508 * Create a test group member
509 * @param array|stdClass $record
510 * @throws coding_exception
511 * @return boolean
512 */
513 public function create_group_member($record) {
514 global $DB, $CFG;
515
516 require_once($CFG->dirroot . '/group/lib.php');
517
518 $record = (array)$record;
519
520 if (empty($record['userid'])) {
521 throw new coding_exception('user must be present in testing_util::create_group_member() $record');
522 }
523
524 if (!isset($record['groupid'])) {
525 throw new coding_exception('group must be present in testing_util::create_group_member() $record');
526 }
527
528 if (!isset($record['component'])) {
529 $record['component'] = null;
530 }
531 if (!isset($record['itemid'])) {
532 $record['itemid'] = 0;
533 }
534
535 return groups_add_member($record['groupid'], $record['userid'], $record['component'], $record['itemid']);
536 }
537
7e7cfe7a
PS
538 /**
539 * Create a test grouping for the specified course
540 *
541 * $record should be either an array or a stdClass containing infomation about the grouping to create.
542 * At the very least it needs to contain courseid.
543 * Default values are added for name, description, and descriptionformat if they are not present.
544 *
6b219869
DM
545 * This function calls groups_create_grouping() to create the grouping within the database.
546 * @see groups_create_grouping
7e7cfe7a
PS
547 * @param array|stdClass $record
548 * @return stdClass grouping record
549 */
550 public function create_grouping($record) {
551 global $DB, $CFG;
552
553 require_once($CFG->dirroot . '/group/lib.php');
554
555 $this->groupingcount++;
556 $i = $this->groupingcount;
557
558 $record = (array)$record;
559
560 if (empty($record['courseid'])) {
5c3c2c81 561 throw new coding_exception('courseid must be present in testing_data_generator::create_grouping() $record');
7e7cfe7a
PS
562 }
563
564 if (!isset($record['name'])) {
565 $record['name'] = 'grouping-' . $i;
566 }
567
568 if (!isset($record['description'])) {
569 $record['description'] = "Test Grouping $i\n{$this->loremipsum}";
570 }
571
572 if (!isset($record['descriptionformat'])) {
573 $record['descriptionformat'] = FORMAT_MOODLE;
574 }
575
576 $id = groups_create_grouping((object)$record);
577
578 return $DB->get_record('groupings', array('id'=>$id));
579 }
580
87bb583c
DM
581 /**
582 * Create a test grouping group
583 * @param array|stdClass $record
584 * @throws coding_exception
585 * @return boolean
586 */
587 public function create_grouping_group($record) {
588 global $DB, $CFG;
589
590 require_once($CFG->dirroot . '/group/lib.php');
591
592 $record = (array)$record;
593
594 if (empty($record['groupingid'])) {
595 throw new coding_exception('grouping must be present in testing::create_grouping_group() $record');
596 }
597
598 if (!isset($record['groupid'])) {
599 throw new coding_exception('group must be present in testing_util::create_grouping_group() $record');
600 }
601
602 return groups_assign_grouping($record['groupingid'], $record['groupid']);
603 }
604
0852bbae
FM
605 /**
606 * Create an instance of a repository.
607 *
608 * @param string type of repository to create an instance for.
609 * @param array|stdClass $record data to use to up set the instance.
610 * @param array $options options
611 * @return stdClass repository instance record
5bcfd504 612 * @since Moodle 2.5.1
0852bbae
FM
613 */
614 public function create_repository($type, $record=null, array $options = null) {
0852bbae
FM
615 $generator = $this->get_plugin_generator('repository_'.$type);
616 return $generator->create_instance($record, $options);
617 }
618
619 /**
620 * Create an instance of a repository.
621 *
622 * @param string type of repository to create an instance for.
623 * @param array|stdClass $record data to use to up set the instance.
624 * @param array $options options
625 * @return repository_type object
5bcfd504 626 * @since Moodle 2.5.1
0852bbae
FM
627 */
628 public function create_repository_type($type, $record=null, array $options = null) {
0852bbae
FM
629 $generator = $this->get_plugin_generator('repository_'.$type);
630 return $generator->create_type($record, $options);
631 }
632
633
7e7cfe7a
PS
634 /**
635 * Create a test scale
636 * @param array|stdClass $record
637 * @param array $options
638 * @return stdClass block instance record
639 */
640 public function create_scale($record=null, array $options=null) {
641 global $DB;
642
643 $this->scalecount++;
644 $i = $this->scalecount;
645
646 $record = (array)$record;
647
648 if (!isset($record['name'])) {
649 $record['name'] = 'Test scale '.$i;
650 }
651
652 if (!isset($record['scale'])) {
653 $record['scale'] = 'A,B,C,D,F';
654 }
655
656 if (!isset($record['courseid'])) {
657 $record['courseid'] = 0;
658 }
659
660 if (!isset($record['userid'])) {
661 $record['userid'] = 0;
662 }
663
664 if (!isset($record['description'])) {
665 $record['description'] = 'Test scale description '.$i;
666 }
667
668 if (!isset($record['descriptionformat'])) {
669 $record['descriptionformat'] = FORMAT_MOODLE;
670 }
671
672 $record['timemodified'] = time();
673
674 if (isset($record['id'])) {
675 $DB->import_record('scale', $record);
676 $DB->get_manager()->reset_sequence('scale');
677 $id = $record['id'];
678 } else {
679 $id = $DB->insert_record('scale', $record);
680 }
681
682 return $DB->get_record('scale', array('id'=>$id), '*', MUST_EXIST);
683 }
4f5789ea 684
702851c0
DM
685 /**
686 * Creates a new role in the system.
687 *
688 * You can fill $record with the role 'name',
689 * 'shortname', 'description' and 'archetype'.
690 *
691 * If an archetype is specified it's capabilities,
692 * context where the role can be assigned and
693 * all other properties are copied from the archetype;
694 * if no archetype is specified it will create an
695 * empty role.
696 *
697 * @param array|stdClass $record
698 * @return int The new role id
699 */
700 public function create_role($record=null) {
701 global $DB;
702
703 $this->rolecount++;
704 $i = $this->rolecount;
705
706 $record = (array)$record;
707
708 if (empty($record['shortname'])) {
709 $record['shortname'] = 'role-' . $i;
710 }
711
712 if (empty($record['name'])) {
713 $record['name'] = 'Test role ' . $i;
714 }
715
716 if (empty($record['description'])) {
717 $record['description'] = 'Test role ' . $i . ' description';
718 }
719
720 if (empty($record['archetype'])) {
721 $record['archetype'] = '';
722 } else {
723 $archetypes = get_role_archetypes();
724 if (empty($archetypes[$record['archetype']])) {
725 throw new coding_exception('\'role\' requires the field \'archetype\' to specify a ' .
726 'valid archetype shortname (editingteacher, student...)');
727 }
728 }
729
730 // Creates the role.
731 if (!$newroleid = create_role($record['name'], $record['shortname'], $record['description'], $record['archetype'])) {
732 throw new coding_exception('There was an error creating \'' . $record['shortname'] . '\' role');
733 }
734
735 // If no archetype was specified we allow it to be added to all contexts,
736 // otherwise we allow it in the archetype contexts.
737 if (!$record['archetype']) {
738 $contextlevels = array_keys(context_helper::get_all_levels());
739 } else {
740 // Copying from the archetype default rol.
741 $archetyperoleid = $DB->get_field(
742 'role',
743 'id',
744 array('shortname' => $record['archetype'], 'archetype' => $record['archetype'])
745 );
746 $contextlevels = get_role_contextlevels($archetyperoleid);
747 }
748 set_role_contextlevels($newroleid, $contextlevels);
749
750 if ($record['archetype']) {
751
752 // We copy all the roles the archetype can assign, override and switch to.
753 if ($record['archetype']) {
754 $types = array('assign', 'override', 'switch');
755 foreach ($types as $type) {
756 $rolestocopy = get_default_role_archetype_allows($type, $record['archetype']);
757 foreach ($rolestocopy as $tocopy) {
758 $functionname = 'allow_' . $type;
759 $functionname($newroleid, $tocopy);
760 }
761 }
762 }
763
764 // Copying the archetype capabilities.
765 $sourcerole = $DB->get_record('role', array('id' => $archetyperoleid));
766 role_cap_duplicate($sourcerole, $newroleid);
767 }
768
769 return $newroleid;
770 }
771
e0c86198
MN
772 /**
773 * Create a tag.
774 *
775 * @param array|stdClass $record
776 * @return stdClass the tag record
777 */
778 public function create_tag($record = null) {
779 global $DB, $USER;
780
781 $this->tagcount++;
782 $i = $this->tagcount;
783
784 $record = (array) $record;
785
786 if (!isset($record['userid'])) {
787 $record['userid'] = $USER->id;
788 }
789
790 if (!isset($record['name'])) {
791 $record['name'] = 'Tag name ' . $i;
792 }
793
794 if (!isset($record['rawname'])) {
795 $record['rawname'] = 'Raw tag name ' . $i;
796 }
797
798 if (!isset($record['tagtype'])) {
799 $record['tagtype'] = 'default';
800 }
801
802 if (!isset($record['description'])) {
803 $record['description'] = 'Tag description';
804 }
805
806 if (!isset($record['descriptionformat'])) {
807 $record['descriptionformat'] = FORMAT_MOODLE;
808 }
809
810 if (!isset($record['flag'])) {
811 $record['flag'] = 0;
812 }
813
814 if (!isset($record['timemodified'])) {
815 $record['timemodified'] = time();
816 }
817
818 $id = $DB->insert_record('tag', $record);
819
820 return $DB->get_record('tag', array('id' => $id), '*', MUST_EXIST);
821 }
822
ba203de1
TH
823 /**
824 * Helper method which combines $defaults with the values specified in $record.
825 * If $record is an object, it is converted to an array.
826 * Then, for each key that is in $defaults, but not in $record, the value
827 * from $defaults is copied.
828 * @param array $defaults the default value for each field with
829 * @param array|stdClass $record
830 * @return array updated $record.
831 */
832 public function combine_defaults_and_record(array $defaults, $record) {
833 $record = (array) $record;
834
835 foreach ($defaults as $key => $defaults) {
836 if (!array_key_exists($key, $record)) {
837 $record[$key] = $defaults;
838 }
839 }
840 return $record;
841 }
842
4f5789ea
PS
843 /**
844 * Simplified enrolment of user to course using default options.
845 *
846 * It is strongly recommended to use only this method for 'manual' and 'self' plugins only!!!
847 *
848 * @param int $userid
849 * @param int $courseid
850 * @param int $roleid optional role id, use only with manual plugin
851 * @param string $enrol name of enrol plugin,
852 * there must be exactly one instance in course,
853 * it must support enrol_user() method.
1ecb8044
RT
854 * @param int $timestart (optional) 0 means unknown
855 * @param int $timeend (optional) 0 means forever
856 * @param int $status (optional) default to ENROL_USER_ACTIVE for new enrolments
4f5789ea
PS
857 * @return bool success
858 */
e6cc5347 859 public function enrol_user($userid, $courseid, $roleid = null, $enrol = 'manual', $timestart = 0, $timeend = 0, $status = null) {
4f5789ea
PS
860 global $DB;
861
862 if (!$plugin = enrol_get_plugin($enrol)) {
863 return false;
864 }
865
866 $instances = $DB->get_records('enrol', array('courseid'=>$courseid, 'enrol'=>$enrol));
867 if (count($instances) != 1) {
868 return false;
869 }
870 $instance = reset($instances);
871
872 if (is_null($roleid) and $instance->roleid) {
873 $roleid = $instance->roleid;
874 }
875
e6cc5347 876 $plugin->enrol_user($instance, $userid, $roleid, $timestart, $timeend, $status);
4f5789ea
PS
877 return true;
878 }
72ddc05f
DM
879
880 /**
881 * Assigns the specified role to a user in the context.
882 *
883 * @param int $roleid
884 * @param int $userid
885 * @param int $contextid Defaults to the system context
886 * @return int new/existing id of the assignment
887 */
888 public function role_assign($roleid, $userid, $contextid = false) {
889
890 // Default to the system context.
891 if (!$contextid) {
892 $context = context_system::instance();
893 $contextid = $context->id;
894 }
895
896 if (empty($roleid)) {
897 throw new coding_exception('roleid must be present in testing_data_generator::role_assign() arguments');
898 }
899
900 if (empty($userid)) {
901 throw new coding_exception('userid must be present in testing_data_generator::role_assign() arguments');
902 }
903
904 return role_assign($roleid, $userid, $contextid);
905 }
906
15ace204
DW
907 /**
908 * Create a grade_category.
909 *
910 * @param array|stdClass $record
911 * @return stdClass the grade category record
912 */
913 public function create_grade_category($record = null) {
914 global $CFG;
915
916 $this->gradecategorycounter++;
917 $i = $this->gradecategorycounter;
918
f4f2045a
MG
919 $record = (array)$record;
920
921 if (empty($record['courseid'])) {
922 throw new coding_exception('courseid must be present in testing::create_grade_category() $record');
923 }
924
15ace204
DW
925 if (!isset($record['fullname'])) {
926 $record['fullname'] = 'Grade category ' . $i;
927 }
928
929 // For gradelib classes.
930 require_once($CFG->libdir . '/gradelib.php');
931 // Create new grading category in this course.
f4f2045a 932 $gradecategory = new grade_category(array('courseid' => $record['courseid']), false);
15ace204 933 $gradecategory->apply_default_settings();
f4f2045a 934 grade_category::set_properties($gradecategory, $record);
15ace204
DW
935 $gradecategory->apply_forced_settings();
936 $gradecategory->insert();
f4f2045a 937
15ace204
DW
938 // This creates a default grade item for the category
939 $gradeitem = $gradecategory->load_grade_item();
940
15ace204
DW
941 $gradecategory->update_from_db();
942 return $gradecategory->get_record_data();
943 }
7e7cfe7a 944}