Merge branch 'MDL-38582' of git://github.com/timhunt/moodle
[moodle.git] / lib / testing / generator / data_generator.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  * Data generator.
19  *
20  * @package    core
21  * @category   test
22  * @copyright  2012 Petr Skoda {@link http://skodak.org}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
27 /**
28  * Data generator class for unit tests and other tools that need to create fake test sites.
29  *
30  * @package    core
31  * @category   test
32  * @copyright  2012 Petr Skoda {@link http://skodak.org}
33  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34  */
35 class testing_data_generator {
36     protected $usercounter = 0;
37     protected $categorycount = 0;
38     protected $cohortcount = 0;
39     protected $coursecount = 0;
40     protected $scalecount = 0;
41     protected $groupcount = 0;
42     protected $groupingcount = 0;
44     /** @var array list of plugin generators */
45     protected $generators = array();
47     /** @var array lis of common last names */
48     public $lastnames = array(
49         'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Miller', 'Davis', 'García', 'Rodríguez', 'Wilson',
50         'Müller', 'Schmidt', 'Schneider', 'Fischer', 'Meyer', 'Weber', 'Schulz', 'Wagner', 'Becker', 'Hoffmann',
51         'Novák', 'Svoboda', 'Novotný', 'Dvořák', 'Černý', 'Procházková', 'Kučerová', 'Veselá', 'Horáková', 'Němcová',
52         'Смирнов', 'Иванов', 'Кузнецов', 'Соколов', 'Попов', 'Лебедева', 'Козлова', 'Новикова', 'Морозова', 'Петрова',
53         '王', '李', '张', '刘', '陈', '楊', '黃', '趙', '吳', '周',
54         '佐藤', '鈴木', '高橋', '田中', '渡辺', '伊藤', '山本', '中村', '小林', '斎藤',
55     );
57     /** @var array lis of common first names */
58     public $firstnames = array(
59         'Jacob', 'Ethan', 'Michael', 'Jayden', 'William', 'Isabella', 'Sophia', 'Emma', 'Olivia', 'Ava',
60         'Lukas', 'Leon', 'Luca', 'Timm', 'Paul', 'Leonie', 'Leah', 'Lena', 'Hanna', 'Laura',
61         'Jakub', 'Jan', 'Tomáš', 'Lukáš', 'Matěj', 'Tereza', 'Eliška', 'Anna', 'Adéla', 'Karolína',
62         'Даниил', 'Максим', 'Артем', 'Иван', 'Александр', 'София', 'Анастасия', 'Дарья', 'Мария', 'Полина',
63         '伟', '伟', '芳', '伟', '秀英', '秀英', '娜', '秀英', '伟', '敏',
64         '翔', '大翔', '拓海', '翔太', '颯太', '陽菜', 'さくら', '美咲', '葵', '美羽',
65     );
67     public $loremipsum = <<<EOD
68 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.
69 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.
70 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.
71 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.
72 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.
73 EOD;
75     /**
76      * To be called from data reset code only,
77      * do not use in tests.
78      * @return void
79      */
80     public function reset() {
81         $this->usercounter = 0;
82         $this->categorycount = 0;
83         $this->coursecount = 0;
84         $this->scalecount = 0;
86         foreach ($this->generators as $generator) {
87             $generator->reset();
88         }
89     }
91     /**
92      * Return generator for given plugin or component.
93      * @param string $component the component name, e.g. 'mod_forum' or 'core_question'.
94      * @return component_generator_base or rather an instance of the appropriate subclass.
95      */
96     public function get_plugin_generator($component) {
97         list($type, $plugin) = normalize_component($component);
98         $cleancomponent = $type . '_' . $plugin;
99         if ($cleancomponent != $component) {
100             debugging("Please specify the component you want a generator for as " .
101                     "{$cleancomponent}, not {$component}.", DEBUG_DEVELOPER);
102             $component = $cleancomponent;
103         }
105         if (isset($this->generators[$component])) {
106             return $this->generators[$component];
107         }
109         $dir = get_component_directory($component);
110         $lib = $dir . '/tests/generator/lib.php';
111         if (!$dir || !is_readable($lib)) {
112             throw new coding_exception("Component {$component} does not support " .
113                     "generators yet. Missing tests/generator/lib.php.");
114         }
116         include_once($lib);
117         $classname = $component . '_generator';
119         if (!class_exists($classname)) {
120             throw new coding_exception("Component {$component} does not support " .
121                     "data generators yet. Class {$classname} not found.");
122         }
124         $this->generators[$component] = new $classname($this);
125         return $this->generators[$component];
126     }
128     /**
129      * Create a test user
130      * @param array|stdClass $record
131      * @param array $options
132      * @return stdClass user record
133      */
134     public function create_user($record=null, array $options=null) {
135         global $DB, $CFG;
137         $this->usercounter++;
138         $i = $this->usercounter;
140         $record = (array)$record;
142         if (!isset($record['auth'])) {
143             $record['auth'] = 'manual';
144         }
146         if (!isset($record['firstname']) and !isset($record['lastname'])) {
147             $country = rand(0, 5);
148             $firstname = rand(0, 4);
149             $lastname = rand(0, 4);
150             $female = rand(0, 1);
151             $record['firstname'] = $this->firstnames[($country*10) + $firstname + ($female*5)];
152             $record['lastname'] = $this->lastnames[($country*10) + $lastname + ($female*5)];
154         } else if (!isset($record['firstname'])) {
155             $record['firstname'] = 'Firstname'.$i;
157         } else if (!isset($record['lastname'])) {
158             $record['lastname'] = 'Lastname'.$i;
159         }
161         if (!isset($record['idnumber'])) {
162             $record['idnumber'] = '';
163         }
165         if (!isset($record['mnethostid'])) {
166             $record['mnethostid'] = $CFG->mnet_localhost_id;
167         }
169         if (!isset($record['username'])) {
170             $record['username'] = 'username'.$i;
171             $j = 2;
172             while ($DB->record_exists('user', array('username'=>$record['username'], 'mnethostid'=>$record['mnethostid']))) {
173                 $record['username'] = 'username'.$i.'_'.$j;
174                 $j++;
175             }
176         }
178         if (isset($record['password'])) {
179             $record['password'] = hash_internal_user_password($record['password']);
180         } else {
181             // The auth plugin may not fully support this,
182             // but it is still better/faster than hashing random stuff.
183             $record['password'] = AUTH_PASSWORD_NOT_CACHED;
184         }
186         if (!isset($record['email'])) {
187             $record['email'] = $record['username'].'@example.com';
188         }
190         if (!isset($record['confirmed'])) {
191             $record['confirmed'] = 1;
192         }
194         if (!isset($record['lang'])) {
195             $record['lang'] = 'en';
196         }
198         if (!isset($record['maildisplay'])) {
199             $record['maildisplay'] = 1;
200         }
202         if (!isset($record['deleted'])) {
203             $record['deleted'] = 0;
204         }
206         $record['timecreated'] = time();
207         $record['timemodified'] = $record['timecreated'];
208         $record['lastip'] = '0.0.0.0';
210         if ($record['deleted']) {
211             $delname = $record['email'].'.'.time();
212             while ($DB->record_exists('user', array('username'=>$delname))) {
213                 $delname++;
214             }
215             $record['idnumber'] = '';
216             $record['email']    = md5($record['username']);
217             $record['username'] = $delname;
218             $record['picture']  = 0;
219         }
221         $userid = $DB->insert_record('user', $record);
223         if (!$record['deleted']) {
224             context_user::instance($userid);
225         }
227         return $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
228     }
230     /**
231      * Create a test course category
232      * @param array|stdClass $record
233      * @param array $options
234      * @return coursecat course category record
235      */
236     public function create_category($record=null, array $options=null) {
237         global $DB, $CFG;
238         require_once("$CFG->libdir/coursecatlib.php");
240         $this->categorycount++;
241         $i = $this->categorycount;
243         $record = (array)$record;
245         if (!isset($record['name'])) {
246             $record['name'] = 'Course category '.$i;
247         }
249         if (!isset($record['description'])) {
250             $record['description'] = "Test course category $i\n$this->loremipsum";
251         }
253         if (!isset($record['idnumber'])) {
254             $record['idnumber'] = '';
255         }
257         return coursecat::create($record);
258     }
260     /**
261      * Create test cohort.
262      * @param array|stdClass $record
263      * @param array $options
264      * @return stdClass cohort record
265      */
266     public function create_cohort($record=null, array $options=null) {
267         global $DB, $CFG;
268         require_once("$CFG->dirroot/cohort/lib.php");
270         $this->cohortcount++;
271         $i = $this->cohortcount;
273         $record = (array)$record;
275         if (!isset($record['contextid'])) {
276             $record['contextid'] = context_system::instance()->id;
277         }
279         if (!isset($record['name'])) {
280             $record['name'] = 'Cohort '.$i;
281         }
283         if (!isset($record['idnumber'])) {
284             $record['idnumber'] = '';
285         }
287         if (!isset($record['description'])) {
288             $record['description'] = "Test cohort $i\n$this->loremipsum";
289         }
291         if (!isset($record['descriptionformat'])) {
292             $record['descriptionformat'] = FORMAT_MOODLE;
293         }
295         if (!isset($record['component'])) {
296             $record['component'] = '';
297         }
299         $id = cohort_add_cohort((object)$record);
301         return $DB->get_record('cohort', array('id'=>$id), '*', MUST_EXIST);
302     }
304     /**
305      * Create a test course
306      * @param array|stdClass $record
307      * @param array $options with keys:
308      *      'createsections'=>bool precreate all sections
309      * @return stdClass course record
310      */
311     public function create_course($record=null, array $options=null) {
312         global $DB, $CFG;
313         require_once("$CFG->dirroot/course/lib.php");
315         $this->coursecount++;
316         $i = $this->coursecount;
318         $record = (array)$record;
320         if (!isset($record['fullname'])) {
321             $record['fullname'] = 'Test course '.$i;
322         }
324         if (!isset($record['shortname'])) {
325             $record['shortname'] = 'tc_'.$i;
326         }
328         if (!isset($record['idnumber'])) {
329             $record['idnumber'] = '';
330         }
332         if (!isset($record['format'])) {
333             $record['format'] = 'topics';
334         }
336         if (!isset($record['newsitems'])) {
337             $record['newsitems'] = 0;
338         }
340         if (!isset($record['numsections'])) {
341             $record['numsections'] = 5;
342         }
344         if (!isset($record['summary'])) {
345             $record['summary'] = "Test course $i\n$this->loremipsum";
346         }
348         if (!isset($record['summaryformat'])) {
349             $record['summaryformat'] = FORMAT_MOODLE;
350         }
352         if (!isset($record['category'])) {
353             $record['category'] = $DB->get_field_select('course_categories', "MIN(id)", "parent=0");
354         }
356         $course = create_course((object)$record);
357         context_course::instance($course->id);
358         if (!empty($options['createsections'])) {
359             if (isset($course->numsections)) {
360                 course_create_sections_if_missing($course, range(0, $course->numsections));
361             } else {
362                 course_create_sections_if_missing($course, 0);
363             }
364         }
366         return $course;
367     }
369     /**
370      * Create course section if does not exist yet
371      * @param array|stdClass $record must contain 'course' and 'section' attributes
372      * @param array|null $options
373      * @return stdClass
374      * @throws coding_exception
375      */
376     public function create_course_section($record = null, array $options = null) {
377         global $DB;
379         $record = (array)$record;
381         if (empty($record['course'])) {
382             throw new coding_exception('course must be present in testing_data_generator::create_course_section() $record');
383         }
385         if (!isset($record['section'])) {
386             throw new coding_exception('section must be present in testing_data_generator::create_course_section() $record');
387         }
389         course_create_sections_if_missing($record['course'], $record['section']);
390         return get_fast_modinfo($record['course'])->get_section_info($record['section']);
391     }
393     /**
394      * Create a test block
395      * @param string $blockname
396      * @param array|stdClass $record
397      * @param array $options
398      * @return stdClass block instance record
399      */
400     public function create_block($blockname, $record=null, array $options=null) {
401         $generator = $this->get_plugin_generator('block_'.$blockname);
402         return $generator->create_instance($record, $options);
403     }
405     /**
406      * Create a test module
407      * @param string $modulename
408      * @param array|stdClass $record
409      * @param array $options
410      * @return stdClass activity record
411      */
412     public function create_module($modulename, $record=null, array $options=null) {
413         $generator = $this->get_plugin_generator('mod_'.$modulename);
414         return $generator->create_instance($record, $options);
415     }
417     /**
418      * Create a test group for the specified course
419      *
420      * $record should be either an array or a stdClass containing infomation about the group to create.
421      * At the very least it needs to contain courseid.
422      * Default values are added for name, description, and descriptionformat if they are not present.
423      *
424      * This function calls groups_create_group() to create the group within the database.
425      * @see groups_create_group
426      * @param array|stdClass $record
427      * @return stdClass group record
428      */
429     public function create_group($record) {
430         global $DB, $CFG;
432         require_once($CFG->dirroot . '/group/lib.php');
434         $this->groupcount++;
435         $i = $this->groupcount;
437         $record = (array)$record;
439         if (empty($record['courseid'])) {
440             throw new coding_exception('courseid must be present in testing_data_generator::create_group() $record');
441         }
443         if (!isset($record['name'])) {
444             $record['name'] = 'group-' . $i;
445         }
447         if (!isset($record['description'])) {
448             $record['description'] = "Test Group $i\n{$this->loremipsum}";
449         }
451         if (!isset($record['descriptionformat'])) {
452             $record['descriptionformat'] = FORMAT_MOODLE;
453         }
455         $id = groups_create_group((object)$record);
457         return $DB->get_record('groups', array('id'=>$id));
458     }
460     /**
461      * Create a test group member
462      * @param array|stdClass $record
463      * @throws coding_exception
464      * @return boolean
465      */
466     public function create_group_member($record) {
467         global $DB, $CFG;
469         require_once($CFG->dirroot . '/group/lib.php');
471         $record = (array)$record;
473         if (empty($record['userid'])) {
474             throw new coding_exception('user must be present in testing_util::create_group_member() $record');
475         }
477         if (!isset($record['groupid'])) {
478             throw new coding_exception('group must be present in testing_util::create_group_member() $record');
479         }
481         if (!isset($record['component'])) {
482             $record['component'] = null;
483         }
484         if (!isset($record['itemid'])) {
485             $record['itemid'] = 0;
486         }
488         return groups_add_member($record['groupid'], $record['userid'], $record['component'], $record['itemid']);
489     }
491     /**
492      * Create a test grouping for the specified course
493      *
494      * $record should be either an array or a stdClass containing infomation about the grouping to create.
495      * At the very least it needs to contain courseid.
496      * Default values are added for name, description, and descriptionformat if they are not present.
497      *
498      * This function calls groups_create_grouping() to create the grouping within the database.
499      * @see groups_create_grouping
500      * @param array|stdClass $record
501      * @return stdClass grouping record
502      */
503     public function create_grouping($record) {
504         global $DB, $CFG;
506         require_once($CFG->dirroot . '/group/lib.php');
508         $this->groupingcount++;
509         $i = $this->groupingcount;
511         $record = (array)$record;
513         if (empty($record['courseid'])) {
514             throw new coding_exception('courseid must be present in testing_data_generator::create_grouping() $record');
515         }
517         if (!isset($record['name'])) {
518             $record['name'] = 'grouping-' . $i;
519         }
521         if (!isset($record['description'])) {
522             $record['description'] = "Test Grouping $i\n{$this->loremipsum}";
523         }
525         if (!isset($record['descriptionformat'])) {
526             $record['descriptionformat'] = FORMAT_MOODLE;
527         }
529         $id = groups_create_grouping((object)$record);
531         return $DB->get_record('groupings', array('id'=>$id));
532     }
534     /**
535      * Create a test grouping group
536      * @param array|stdClass $record
537      * @throws coding_exception
538      * @return boolean
539      */
540     public function create_grouping_group($record) {
541         global $DB, $CFG;
543         require_once($CFG->dirroot . '/group/lib.php');
545         $record = (array)$record;
547         if (empty($record['groupingid'])) {
548             throw new coding_exception('grouping must be present in testing::create_grouping_group() $record');
549         }
551         if (!isset($record['groupid'])) {
552             throw new coding_exception('group must be present in testing_util::create_grouping_group() $record');
553         }
555         return groups_assign_grouping($record['groupingid'], $record['groupid']);
556     }
558     /**
559      * Create a test scale
560      * @param array|stdClass $record
561      * @param array $options
562      * @return stdClass block instance record
563      */
564     public function create_scale($record=null, array $options=null) {
565         global $DB;
567         $this->scalecount++;
568         $i = $this->scalecount;
570         $record = (array)$record;
572         if (!isset($record['name'])) {
573             $record['name'] = 'Test scale '.$i;
574         }
576         if (!isset($record['scale'])) {
577             $record['scale'] = 'A,B,C,D,F';
578         }
580         if (!isset($record['courseid'])) {
581             $record['courseid'] = 0;
582         }
584         if (!isset($record['userid'])) {
585             $record['userid'] = 0;
586         }
588         if (!isset($record['description'])) {
589             $record['description'] = 'Test scale description '.$i;
590         }
592         if (!isset($record['descriptionformat'])) {
593             $record['descriptionformat'] = FORMAT_MOODLE;
594         }
596         $record['timemodified'] = time();
598         if (isset($record['id'])) {
599             $DB->import_record('scale', $record);
600             $DB->get_manager()->reset_sequence('scale');
601             $id = $record['id'];
602         } else {
603             $id = $DB->insert_record('scale', $record);
604         }
606         return $DB->get_record('scale', array('id'=>$id), '*', MUST_EXIST);
607     }
609     /**
610      * Helper method which combines $defaults with the values specified in $record.
611      * If $record is an object, it is converted to an array.
612      * Then, for each key that is in $defaults, but not in $record, the value
613      * from $defaults is copied.
614      * @param array $defaults the default value for each field with
615      * @param array|stdClass $record
616      * @return array updated $record.
617      */
618     public function combine_defaults_and_record(array $defaults, $record) {
619         $record = (array) $record;
621         foreach ($defaults as $key => $defaults) {
622             if (!array_key_exists($key, $record)) {
623                 $record[$key] = $defaults;
624             }
625         }
626         return $record;
627     }
629     /**
630      * Simplified enrolment of user to course using default options.
631      *
632      * It is strongly recommended to use only this method for 'manual' and 'self' plugins only!!!
633      *
634      * @param int $userid
635      * @param int $courseid
636      * @param int $roleid optional role id, use only with manual plugin
637      * @param string $enrol name of enrol plugin,
638      *     there must be exactly one instance in course,
639      *     it must support enrol_user() method.
640      * @return bool success
641      */
642     public function enrol_user($userid, $courseid, $roleid = null, $enrol = 'manual') {
643         global $DB;
645         if (!$plugin = enrol_get_plugin($enrol)) {
646             return false;
647         }
649         $instances = $DB->get_records('enrol', array('courseid'=>$courseid, 'enrol'=>$enrol));
650         if (count($instances) != 1) {
651             return false;
652         }
653         $instance = reset($instances);
655         if (is_null($roleid) and $instance->roleid) {
656             $roleid = $instance->roleid;
657         }
659         $plugin->enrol_user($instance, $userid, $roleid);
661         return true;
662     }
665 /**
666  * Deprecated in favour of testing_data_generator
667  *
668  * @deprecated since Moodle 2.5 MDL-37457 - please do not use this function any more.
669  * @todo       MDL-37517 This will be deleted in Moodle 2.7
670  * @see        testing_data_generator
671  * @package    core
672  * @category   test
673  * @copyright  2012 David Monllaó
674  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
675  */
676 class phpunit_data_generator extends testing_data_generator {
678     /**
679      * Dumb constructor to throw the deprecated notification
680      */
681     public function __construct() {
682         debugging('Class phpunit_data_generator is deprecated, please use class testing_module_generator instead', DEBUG_DEVELOPER);
683     }