Merge branch 'MDL-32426-master-1' of git://git.luns.net.uk/moodle
[moodle.git] / lib / phpunit / generatorlib.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  * PHPUnit data generator class
19  *
20  * @package    core
21  * @category   phpunit
22  * @copyright  2012 Petr Skoda {@link http://skodak.org}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
29 /**
30  * Data generator for unit tests
31  *
32  * @package    core
33  * @category   phpunit
34  * @copyright  2012 Petr Skoda {@link http://skodak.org}
35  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36  */
37 class phpunit_data_generator {
38     protected $usercounter = 0;
39     protected $categorycount = 0;
40     protected $coursecount = 0;
41     protected $scalecount = 0;
42     protected $groupcount = 0;
43     protected $groupingcount = 0;
45     /** @var array list of plugin generators */
46     protected $generators = array();
48     /** @var array lis of common last names */
49     public $lastnames = array(
50         'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Miller', 'Davis', 'García', 'Rodríguez', 'Wilson',
51         'Müller', 'Schmidt', 'Schneider', 'Fischer', 'Meyer', 'Weber', 'Schulz', 'Wagner', 'Becker', 'Hoffmann',
52         'Novák', 'Svoboda', 'Novotný', 'Dvořák', 'Černý', 'Procházková', 'Kučerová', 'Veselá', 'Horáková', 'Němcová',
53         'Смирнов', 'Иванов', 'Кузнецов', 'Соколов', 'Попов', 'Лебедева', 'Козлова', 'Новикова', 'Морозова', 'Петрова',
54         '王', '李', '张', '刘', '陈', '楊', '黃', '趙', '吳', '周',
55         '佐藤', '鈴木', '高橋', '田中', '渡辺', '伊藤', '山本', '中村', '小林', '斎藤',
56     );
58     /** @var array lis of common first names */
59     public $firstnames = array(
60         'Jacob', 'Ethan', 'Michael', 'Jayden', 'William', 'Isabella', 'Sophia', 'Emma', 'Olivia', 'Ava',
61         'Lukas', 'Leon', 'Luca', 'Timm', 'Paul', 'Leonie', 'Leah', 'Lena', 'Hanna', 'Laura',
62         'Jakub', 'Jan', 'Tomáš', 'Lukáš', 'Matěj', 'Tereza', 'Eliška', 'Anna', 'Adéla', 'Karolína',
63         'Даниил', 'Максим', 'Артем', 'Иван', 'Александр', 'София', 'Анастасия', 'Дарья', 'Мария', 'Полина',
64         '伟', '伟', '芳', '伟', '秀英', '秀英', '娜', '秀英', '伟', '敏',
65         '翔', '大翔', '拓海', '翔太', '颯太', '陽菜', 'さくら', '美咲', '葵', '美羽',
66     );
68     public $loremipsum = <<<EOD
69 Lorem 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.
70 Temporibus 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.
71 Vivamus 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.
72 Integer 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.
73 In 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.
74 EOD;
76     /**
77      * To be called from data reset code only,
78      * do not use in tests.
79      * @return void
80      */
81     public function reset() {
82         $this->usercounter = 0;
83         $this->categorycount = 0;
84         $this->coursecount = 0;
85         $this->scalecount = 0;
87         foreach($this->generators as $generator) {
88             $generator->reset();
89         }
90     }
92     /**
93      * Return generator for given plugin
94      * @param string $component
95      * @return mixed plugin data generator
96      */
97     public function get_plugin_generator($component) {
98         list($type, $plugin) = normalize_component($component);
100         if ($type !== 'mod' and $type !== 'block') {
101             throw new coding_exception("Plugin type $type does not support generators yet");
102         }
104         $dir = get_plugin_directory($type, $plugin);
106         if (!isset($this->generators[$type.'_'.$plugin])) {
107             $lib = "$dir/tests/generator/lib.php";
108             if (!include_once($lib)) {
109                 throw new coding_exception("Plugin $component does not support data generator, missing tests/generator/lib");
110             }
111             $classname = $type.'_'.$plugin.'_generator';
112             $this->generators[$type.'_'.$plugin] = new $classname($this);
113         }
115         return $this->generators[$type.'_'.$plugin];
116     }
118     /**
119      * Create a test user
120      * @param array|stdClass $record
121      * @param array $options
122      * @return stdClass user record
123      */
124     public function create_user($record=null, array $options=null) {
125         global $DB, $CFG;
127         $this->usercounter++;
128         $i = $this->usercounter;
130         $record = (array)$record;
132         if (!isset($record['auth'])) {
133             $record['auth'] = 'manual';
134         }
136         if (!isset($record['firstname']) and !isset($record['lastname'])) {
137             $country = rand(0, 5);
138             $firstname = rand(0, 4);
139             $lastname = rand(0, 4);
140             $female = rand(0, 1);
141             $record['firstname'] = $this->firstnames[($country*10) + $firstname + ($female*5)];
142             $record['lastname'] = $this->lastnames[($country*10) + $lastname + ($female*5)];
144         } else if (!isset($record['firstname'])) {
145             $record['firstname'] = 'Firstname'.$i;
147         } else if (!isset($record['lastname'])) {
148             $record['lastname'] = 'Lastname'.$i;
149         }
151         if (!isset($record['idnumber'])) {
152             $record['idnumber'] = '';
153         }
155         if (!isset($record['mnethostid'])) {
156             $record['mnethostid'] = $CFG->mnet_localhost_id;
157         }
159         if (!isset($record['username'])) {
160             $record['username'] = textlib::strtolower($record['firstname']).textlib::strtolower($record['lastname']);
161             while ($DB->record_exists('user', array('username'=>$record['username'], 'mnethostid'=>$record['mnethostid']))) {
162                 $record['username'] = $record['username'].'_'.$i;
163             }
164         }
166         if (!isset($record['password'])) {
167             $record['password'] = 'lala';
168         }
170         if (!isset($record['email'])) {
171             $record['email'] = $record['username'].'@example.com';
172         }
174         if (!isset($record['confirmed'])) {
175             $record['confirmed'] = 1;
176         }
178         if (!isset($record['lang'])) {
179             $record['lang'] = 'en';
180         }
182         if (!isset($record['maildisplay'])) {
183             $record['maildisplay'] = 1;
184         }
186         if (!isset($record['deleted'])) {
187             $record['deleted'] = 0;
188         }
190         $record['timecreated'] = time();
191         $record['timemodified'] = $record['timecreated'];
192         $record['lastip'] = '0.0.0.0';
194         $record['password'] = hash_internal_user_password($record['password']);
196         if ($record['deleted']) {
197             $delname = $record['email'].'.'.time();
198             while ($DB->record_exists('user', array('username'=>$delname))) {
199                 $delname++;
200             }
201             $record['idnumber'] = '';
202             $record['email']    = md5($record['username']);
203             $record['username'] = $delname;
204         }
206         $userid = $DB->insert_record('user', $record);
208         if (!$record['deleted']) {
209             context_user::instance($userid);
210         }
212         return $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
213     }
215     /**
216      * Create a test course category
217      * @param array|stdClass $record
218      * @param array $options
219      * @return stdClass course category record
220      */
221     function create_category($record=null, array $options=null) {
222         global $DB, $CFG;
223         require_once("$CFG->dirroot/course/lib.php");
225         $this->categorycount++;
226         $i = $this->categorycount;
228         $record = (array)$record;
230         if (!isset($record['name'])) {
231             $record['name'] = 'Course category '.$i;
232         }
234         if (!isset($record['idnumber'])) {
235             $record['idnumber'] = '';
236         }
238         if (!isset($record['description'])) {
239             $record['description'] = "Test course category $i\n$this->loremipsum";
240         }
242         if (!isset($record['descriptionformat'])) {
243             $record['description'] = FORMAT_MOODLE;
244         }
246         if (!isset($record['parent'])) {
247             $record['descriptionformat'] = 0;
248         }
250         if (empty($record['parent'])) {
251             $parent = new stdClass();
252             $parent->path = '';
253             $parent->depth = 0;
254         } else {
255             $parent = $DB->get_record('course_categories', array('id'=>$record['parent']), '*', MUST_EXIST);
256         }
257         $record['depth'] = $parent->depth+1;
259         $record['sortorder'] = 0;
260         $record['timemodified'] = time();
261         $record['timecreated'] = $record['timemodified'];
263         $catid = $DB->insert_record('course_categories', $record);
264         $path = $parent->path . '/' . $catid;
265         $DB->set_field('course_categories', 'path', $path, array('id'=>$catid));
266         context_coursecat::instance($catid);
268         fix_course_sortorder();
270         return $DB->get_record('course_categories', array('id'=>$catid), '*', MUST_EXIST);
271     }
273     /**
274      * Create a test course
275      * @param array|stdClass $record
276      * @param array $options with keys:
277      *      'createsections'=>bool precreate all sections
278      * @return stdClass course record
279      */
280     function create_course($record=null, array $options=null) {
281         global $DB, $CFG;
282         require_once("$CFG->dirroot/course/lib.php");
284         $this->coursecount++;
285         $i = $this->coursecount;
287         $record = (array)$record;
289         if (!isset($record['fullname'])) {
290             $record['fullname'] = 'Test course '.$i;
291         }
293         if (!isset($record['shortname'])) {
294             $record['shortname'] = 'tc_'.$i;
295         }
297         if (!isset($record['idnumber'])) {
298             $record['idnumber'] = '';
299         }
301         if (!isset($record['format'])) {
302             $record['format'] = 'topics';
303         }
305         if (!isset($record['newsitems'])) {
306             $record['newsitems'] = 0;
307         }
309         if (!isset($record['numsections'])) {
310             $record['numsections'] = 5;
311         }
313         if (!isset($record['description'])) {
314             $record['description'] = "Test course $i\n$this->loremipsum";
315         }
317         if (!isset($record['descriptionformat'])) {
318             $record['description'] = FORMAT_MOODLE;
319         }
321         if (!isset($record['category'])) {
322             $record['category'] = $DB->get_field_select('course_categories', "MIN(id)", "parent=0");
323         }
325         $course = create_course((object)$record);
326         context_course::instance($course->id);
328         if (!empty($options['createsections'])) {
329             for($i=1; $i<$record['numsections']; $i++) {
330                 self::create_course_section(array('course'=>$course->id, 'section'=>$i));
331             }
332         }
334         return $course;
335     }
337     /**
338      * Create course section if does not exist yet
339      * @param mixed $record
340      * @param array|null $options
341      * @return stdClass
342      * @throws coding_exception
343      */
344     public function create_course_section($record = null, array $options = null) {
345         global $DB;
347         $record = (array)$record;
349         if (empty($record['course'])) {
350             throw new coding_exception('course must be present in phpunit_util::create_course_section() $record');
351         }
353         if (!isset($record['section'])) {
354             throw new coding_exception('section must be present in phpunit_util::create_course_section() $record');
355         }
357         if (!isset($record['name'])) {
358             $record['name'] = '';
359         }
361         if (!isset($record['summary'])) {
362             $record['summary'] = '';
363         }
365         if (!isset($record['summaryformat'])) {
366             $record['summaryformat'] = FORMAT_MOODLE;
367         }
369         if ($section = $DB->get_record('course_sections', array('course'=>$record['course'], 'section'=>$record['section']))) {
370             return $section;
371         }
373         $section = new stdClass();
374         $section->course        = $record['course'];
375         $section->section       = $record['section'];
376         $section->name          = $record['name'];
377         $section->summary       = $record['summary'];
378         $section->summaryformat = $record['summaryformat'];
379         $id = $DB->insert_record('course_sections', $section);
381         return $DB->get_record('course_sections', array('id'=>$id));
382     }
384     /**
385      * Create a test block
386      * @param string $blockname
387      * @param array|stdClass $record
388      * @param array $options
389      * @return stdClass block instance record
390      */
391     public function create_block($blockname, $record=null, array $options=null) {
392         $generator = $this->get_plugin_generator('block_'.$blockname);
393         return $generator->create_instance($record, $options);
394     }
396     /**
397      * Create a test module
398      * @param string $modulename
399      * @param array|stdClass $record
400      * @param array $options
401      * @return stdClass activity record
402      */
403     public function create_module($modulename, $record=null, array $options=null) {
404         $generator = $this->get_plugin_generator('mod_'.$modulename);
405         return $generator->create_instance($record, $options);
406     }
408     /**
409      * Create a test group for the specified course
410      *
411      * @param array|stdClass $recrd
412      * @return stdClass group record
413      */
414     public function create_group($record) {
415         global $DB, $CFG;
417         require_once($CFG->dirroot . '/group/lib.php');
419         $this->groupcount++;
420         $i = $this->groupcount;
422         $record = (array)$record;
424         if (empty($record['courseid'])) {
425             throw new coding_exception('courseid must be present in phpunit_util::create_group() $record');
426         }
428         if (!isset($record['name'])) {
429             $record['name'] = 'group-' . $i;
430         }
432         if (!isset($record['description'])) {
433             $record['description'] = "Test Group $i\n{$this->loremipsum}";
434         }
436         if (!isset($record['descriptionformat'])) {
437             $record['descriptionformat'] = FORMAT_MOODLE;
438         }
440         $id = groups_create_group((object)$record);
442         return $DB->get_record('groups', array('id'=>$id));
443     }
445     /**
446      * Create a test grouping for the specified course
447      *
448      * @param array|stdClass $recrd
449      * @return stdClass grouping record
450      */
451     public function create_grouping($record) {
452         global $DB, $CFG;
454         require_once($CFG->dirroot . '/group/lib.php');
456         $this->groupingcount++;
457         $i = $this->groupingcount;
459         $record = (array)$record;
461         if (empty($record['courseid'])) {
462             throw new coding_exception('courseid must be present in phpunit_util::create_grouping() $record');
463         }
465         if (!isset($record['name'])) {
466             $record['name'] = 'grouping-' . $i;
467         }
469         if (!isset($record['description'])) {
470             $record['description'] = "Test Grouping $i\n{$this->loremipsum}";
471         }
473         if (!isset($record['descriptionformat'])) {
474             $record['descriptionformat'] = FORMAT_MOODLE;
475         }
477         $id = groups_create_grouping((object)$record);
479         return $DB->get_record('groupings', array('id'=>$id));
480     }
482     /**
483      * Create a test scale
484      * @param array|stdClass $record
485      * @param array $options
486      * @return stdClass block instance record
487      */
488     public function create_scale($record=null, array $options=null) {
489         global $DB;
491         $this->scalecount++;
492         $i = $this->scalecount;
494         $record = (array)$record;
496         if (!isset($record['name'])) {
497             $record['name'] = 'Test scale '.$i;
498         }
500         if (!isset($record['scale'])) {
501             $record['scale'] = 'A,B,C,D,F';
502         }
504         if (!isset($record['courseid'])) {
505             $record['courseid'] = 0;
506         }
508         if (!isset($record['userid'])) {
509             $record['userid'] = 0;
510         }
512         if (!isset($record['description'])) {
513             $record['description'] = 'Test scale description '.$i;
514         }
516         if (!isset($record['descriptionformat'])) {
517             $record['descriptionformat'] = FORMAT_MOODLE;
518         }
520         $record['timemodified'] = time();
522         if (isset($record['id'])) {
523             $DB->import_record('scale', $record);
524             $DB->get_manager()->reset_sequence('scale');
525             $id = $record['id'];
526         } else {
527             $id = $DB->insert_record('scale', $record);
528         }
530         return $DB->get_record('scale', array('id'=>$id), '*', MUST_EXIST);
531     }
535 /**
536  * Module generator base class.
537  *
538  * Extend in mod/xxxx/tests/generator/lib.php as class mod_xxxx_generator.
539  *
540  * @package    core
541  * @category   phpunit
542  * @copyright  2012 Petr Skoda {@link http://skodak.org}
543  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
544  */
545 abstract class phpunit_module_generator {
546     /** @var phpunit_data_generator@var  */
547     protected $datagenerator;
549     /** @var number of created instances */
550     protected $instancecount = 0;
552     public function __construct(phpunit_data_generator $datagenerator) {
553         $this->datagenerator = $datagenerator;
554     }
556     /**
557      * To be called from data reset code only,
558      * do not use in tests.
559      * @return void
560      */
561     public function reset() {
562         $this->instancecount = 0;
563     }
565     /**
566      * Returns module name
567      * @return string name of module that this class describes
568      * @throws coding_exception if class invalid
569      */
570     public function get_modulename() {
571         $matches = null;
572         if (!preg_match('/^mod_([a-z0-9]+)_generator$/', get_class($this), $matches)) {
573             throw new coding_exception('Invalid module generator class name: '.get_class($this));
574         }
576         if (empty($matches[1])) {
577             throw new coding_exception('Invalid module generator class name: '.get_class($this));
578         }
579         return $matches[1];
580     }
582     /**
583      * Create course module and link it to course
584      * @param stdClass $instance
585      * @param array $options: section, visible
586      * @return stdClass $cm instance
587      */
588     protected function create_course_module(stdClass $instance, array $options) {
589         global $DB, $CFG;
590         require_once("$CFG->dirroot/course/lib.php");
592         $modulename = $this->get_modulename();
594         $cm = new stdClass();
595         $cm->course             = $instance->course;
596         $cm->module             = $DB->get_field('modules', 'id', array('name'=>$modulename));
597         $cm->instance           = $instance->id;
598         $cm->section            = isset($options['section']) ? $options['section'] : 0;
599         $cm->idnumber           = isset($options['idnumber']) ? $options['idnumber'] : 0;
600         $cm->added              = time();
602         $columns = $DB->get_columns('course_modules');
603         foreach ($options as $key=>$value) {
604             if ($key === 'id' or !isset($columns[$key])) {
605                 continue;
606             }
607             if (property_exists($cm, $key)) {
608                 continue;
609             }
610             $cm->$key = $value;
611         }
613         $cm->id = $DB->insert_record('course_modules', $cm);
614         $cm->coursemodule = $cm->id;
616         add_mod_to_section($cm);
618         $cm = get_coursemodule_from_id($modulename, $cm->id, $cm->course, true, MUST_EXIST);
620         context_module::instance($cm->id);
622         return $cm;
623     }
625     /**
626      * Create a test module
627      * @param array|stdClass $record
628      * @param array $options
629      * @return stdClass activity record
630      */
631     abstract public function create_instance($record = null, array $options = null);
635 /**
636  * Block generator base class.
637  *
638  * Extend in blocks/xxxx/tests/generator/lib.php as class block_xxxx_generator.
639  *
640  * @package    core
641  * @category   phpunit
642  * @copyright  2012 Petr Skoda {@link http://skodak.org}
643  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
644  */
645 abstract class phpunit_block_generator {
646     /** @var phpunit_data_generator@var  */
647     protected $datagenerator;
649     /** @var number of created instances */
650     protected $instancecount = 0;
652     public function __construct(phpunit_data_generator $datagenerator) {
653         $this->datagenerator = $datagenerator;
654     }
656     /**
657      * To be called from data reset code only,
658      * do not use in tests.
659      * @return void
660      */
661     public function reset() {
662         $this->instancecount = 0;
663     }
665     /**
666      * Returns block name
667      * @return string name of block that this class describes
668      * @throws coding_exception if class invalid
669      */
670     public function get_blockname() {
671         $matches = null;
672         if (!preg_match('/^block_([a-z0-9_]+)_generator$/', get_class($this), $matches)) {
673             throw new coding_exception('Invalid block generator class name: '.get_class($this));
674         }
676         if (empty($matches[1])) {
677             throw new coding_exception('Invalid block generator class name: '.get_class($this));
678         }
679         return $matches[1];
680     }
682     /**
683      * Fill in record defaults
684      * @param stdClass $record
685      * @return stdClass
686      */
687     protected function prepare_record(stdClass $record) {
688         $record->blockname = $this->get_blockname();
689         if (!isset($record->parentcontextid)) {
690             $record->parentcontextid = context_system::instance()->id;
691         }
692         if (!isset($record->showinsubcontexts)) {
693             $record->showinsubcontexts = 1;
694         }
695         if (!isset($record->pagetypepattern)) {
696             $record->pagetypepattern = '';
697         }
698         if (!isset($record->subpagepattern)) {
699             $record->subpagepattern = null;
700         }
701         if (!isset($record->defaultregion)) {
702             $record->defaultregion = '';
703         }
704         if (!isset($record->defaultweight)) {
705             $record->defaultweight = '';
706         }
707         if (!isset($record->configdata)) {
708             $record->configdata = null;
709         }
710         return $record;
711     }
713     /**
714      * Create a test block
715      * @param array|stdClass $record
716      * @param array $options
717      * @return stdClass activity record
718      */
719     abstract public function create_instance($record = null, array $options = null);