Commit | Line | Data |
---|---|---|
354b214c 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 | * Course related unit tests | |
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 | */ | |
25 | ||
26 | defined('MOODLE_INTERNAL') || die(); | |
27 | ||
f70bfb84 FM |
28 | global $CFG; |
29 | require_once($CFG->dirroot.'/course/lib.php'); | |
354b214c | 30 | |
8252b7c2 | 31 | class core_course_courselib_testcase extends advanced_testcase { |
354b214c | 32 | |
dd5d933f | 33 | /** |
7bf4f6e9 JM |
34 | * Set forum specific test values for calling create_module(). |
35 | * | |
36 | * @param object $moduleinfo - the moduleinfo to add some specific values - passed in reference. | |
dd5d933f | 37 | */ |
7bf4f6e9 JM |
38 | private function forum_create_set_values(&$moduleinfo) { |
39 | // Completion specific to forum - optional. | |
40 | $moduleinfo->completionposts = 3; | |
41 | $moduleinfo->completiondiscussions = 1; | |
42 | $moduleinfo->completionreplies = 2; | |
dd5d933f | 43 | |
7cb0ea2c | 44 | // Specific values to the Forum module. |
dd5d933f JM |
45 | $moduleinfo->forcesubscribe = FORUM_INITIALSUBSCRIBE; |
46 | $moduleinfo->type = 'single'; | |
7bf4f6e9 JM |
47 | $moduleinfo->trackingtype = FORUM_TRACKING_ON; |
48 | $moduleinfo->maxbytes = 10240; | |
49 | $moduleinfo->maxattachments = 2; | |
50 | ||
7cb0ea2c | 51 | // Post threshold for blocking - specific to forum. |
7bf4f6e9 JM |
52 | $moduleinfo->blockperiod = 60*60*24; |
53 | $moduleinfo->blockafter = 10; | |
54 | $moduleinfo->warnafter = 5; | |
55 | } | |
dd5d933f | 56 | |
7bf4f6e9 JM |
57 | /** |
58 | * Execute test asserts on the saved DB data by create_module($forum). | |
59 | * | |
60 | * @param object $moduleinfo - the specific forum values that were used to create a forum. | |
61 | * @param object $dbmodinstance - the DB values of the created forum. | |
62 | */ | |
63 | private function forum_create_run_asserts($moduleinfo, $dbmodinstance) { | |
64 | // Compare values specific to forums. | |
65 | $this->assertEquals($moduleinfo->forcesubscribe, $dbmodinstance->forcesubscribe); | |
66 | $this->assertEquals($moduleinfo->type, $dbmodinstance->type); | |
67 | $this->assertEquals($moduleinfo->assessed, $dbmodinstance->assessed); | |
68 | $this->assertEquals($moduleinfo->completionposts, $dbmodinstance->completionposts); | |
69 | $this->assertEquals($moduleinfo->completiondiscussions, $dbmodinstance->completiondiscussions); | |
70 | $this->assertEquals($moduleinfo->completionreplies, $dbmodinstance->completionreplies); | |
71 | $this->assertEquals($moduleinfo->scale, $dbmodinstance->scale); | |
72 | $this->assertEquals($moduleinfo->assesstimestart, $dbmodinstance->assesstimestart); | |
73 | $this->assertEquals($moduleinfo->assesstimefinish, $dbmodinstance->assesstimefinish); | |
74 | $this->assertEquals($moduleinfo->rsstype, $dbmodinstance->rsstype); | |
75 | $this->assertEquals($moduleinfo->rssarticles, $dbmodinstance->rssarticles); | |
76 | $this->assertEquals($moduleinfo->trackingtype, $dbmodinstance->trackingtype); | |
77 | $this->assertEquals($moduleinfo->maxbytes, $dbmodinstance->maxbytes); | |
78 | $this->assertEquals($moduleinfo->maxattachments, $dbmodinstance->maxattachments); | |
79 | $this->assertEquals($moduleinfo->blockperiod, $dbmodinstance->blockperiod); | |
80 | $this->assertEquals($moduleinfo->blockafter, $dbmodinstance->blockafter); | |
81 | $this->assertEquals($moduleinfo->warnafter, $dbmodinstance->warnafter); | |
82 | } | |
dd5d933f | 83 | |
7bf4f6e9 JM |
84 | /** |
85 | * Set assign module specific test values for calling create_module(). | |
86 | * | |
87 | * @param object $moduleinfo - the moduleinfo to add some specific values - passed in reference. | |
88 | */ | |
89 | private function assign_create_set_values(&$moduleinfo) { | |
7cb0ea2c | 90 | // Specific values to the Assign module. |
dd5d933f JM |
91 | $moduleinfo->alwaysshowdescription = true; |
92 | $moduleinfo->submissiondrafts = true; | |
93 | $moduleinfo->requiresubmissionstatement = true; | |
94 | $moduleinfo->sendnotifications = true; | |
95 | $moduleinfo->sendlatenotifications = true; | |
7bf4f6e9 JM |
96 | $moduleinfo->duedate = time() + (7 * 24 * 3600); |
97 | $moduleinfo->cutoffdate = time() + (7 * 24 * 3600); | |
98 | $moduleinfo->allowsubmissionsfromdate = time(); | |
dd5d933f JM |
99 | $moduleinfo->teamsubmission = true; |
100 | $moduleinfo->requireallteammemberssubmit = true; | |
101 | $moduleinfo->teamsubmissiongroupingid = true; | |
102 | $moduleinfo->blindmarking = true; | |
7f198356 DW |
103 | $moduleinfo->markingworkflow = true; |
104 | $moduleinfo->markingallocation = true; | |
dd5d933f JM |
105 | $moduleinfo->assignsubmission_onlinetext_enabled = true; |
106 | $moduleinfo->assignsubmission_file_enabled = true; | |
107 | $moduleinfo->assignsubmission_file_maxfiles = 1; | |
108 | $moduleinfo->assignsubmission_file_maxsizebytes = 1000000; | |
109 | $moduleinfo->assignsubmission_comments_enabled = true; | |
110 | $moduleinfo->assignfeedback_comments_enabled = true; | |
111 | $moduleinfo->assignfeedback_offline_enabled = true; | |
112 | $moduleinfo->assignfeedback_file_enabled = true; | |
113 | ||
7cb0ea2c | 114 | // Advanced grading. |
7bf4f6e9 JM |
115 | $gradingmethods = grading_manager::available_methods(); |
116 | $moduleinfo->advancedgradingmethod_submissions = current(array_keys($gradingmethods)); | |
117 | } | |
dd5d933f | 118 | |
7bf4f6e9 JM |
119 | /** |
120 | * Execute test asserts on the saved DB data by create_module($assign). | |
121 | * | |
122 | * @param object $moduleinfo - the specific assign module values that were used to create an assign module. | |
123 | * @param object $dbmodinstance - the DB values of the created assign module. | |
124 | */ | |
125 | private function assign_create_run_asserts($moduleinfo, $dbmodinstance) { | |
126 | global $DB; | |
127 | ||
128 | $this->assertEquals($moduleinfo->alwaysshowdescription, $dbmodinstance->alwaysshowdescription); | |
129 | $this->assertEquals($moduleinfo->submissiondrafts, $dbmodinstance->submissiondrafts); | |
130 | $this->assertEquals($moduleinfo->requiresubmissionstatement, $dbmodinstance->requiresubmissionstatement); | |
131 | $this->assertEquals($moduleinfo->sendnotifications, $dbmodinstance->sendnotifications); | |
132 | $this->assertEquals($moduleinfo->duedate, $dbmodinstance->duedate); | |
133 | $this->assertEquals($moduleinfo->cutoffdate, $dbmodinstance->cutoffdate); | |
134 | $this->assertEquals($moduleinfo->allowsubmissionsfromdate, $dbmodinstance->allowsubmissionsfromdate); | |
135 | $this->assertEquals($moduleinfo->teamsubmission, $dbmodinstance->teamsubmission); | |
136 | $this->assertEquals($moduleinfo->requireallteammemberssubmit, $dbmodinstance->requireallteammemberssubmit); | |
137 | $this->assertEquals($moduleinfo->teamsubmissiongroupingid, $dbmodinstance->teamsubmissiongroupingid); | |
138 | $this->assertEquals($moduleinfo->blindmarking, $dbmodinstance->blindmarking); | |
7f198356 DW |
139 | $this->assertEquals($moduleinfo->markingworkflow, $dbmodinstance->markingworkflow); |
140 | $this->assertEquals($moduleinfo->markingallocation, $dbmodinstance->markingallocation); | |
7bf4f6e9 JM |
141 | // The goal not being to fully test assign_add_instance() we'll stop here for the assign tests - to avoid too many DB queries. |
142 | ||
7cb0ea2c | 143 | // Advanced grading. |
7bf4f6e9 JM |
144 | $contextmodule = context_module::instance($dbmodinstance->id); |
145 | $advancedgradingmethod = $DB->get_record('grading_areas', | |
146 | array('contextid' => $contextmodule->id, | |
147 | 'activemethod' => $moduleinfo->advancedgradingmethod_submissions)); | |
148 | $this->assertEquals($moduleinfo->advancedgradingmethod_submissions, $advancedgradingmethod); | |
149 | } | |
150 | ||
151 | /** | |
152 | * Run some asserts test for a specific module for the function create_module(). | |
153 | * | |
154 | * The function has been created (and is called) for $this->test_create_module(). | |
155 | * Note that the call to MODULE_create_set_values and MODULE_create_run_asserts are done after the common set values/run asserts. | |
156 | * So if you want, you can overwrite the default values/asserts in the respective functions. | |
157 | * @param string $modulename Name of the module ('forum', 'assign', 'book'...). | |
158 | */ | |
159 | private function create_specific_module_test($modulename) { | |
160 | global $DB, $CFG; | |
161 | ||
162 | $this->resetAfterTest(true); | |
163 | ||
164 | $this->setAdminUser(); | |
165 | ||
166 | // Warnings: you'll need to change this line if ever you come to test a module not following Moodle standard. | |
167 | require_once($CFG->dirroot.'/mod/'. $modulename .'/lib.php'); | |
168 | ||
169 | // Enable avaibility. | |
170 | // If not enabled all conditional fields will be ignored. | |
171 | set_config('enableavailability', 1); | |
172 | ||
173 | // Enable course completion. | |
174 | // If not enabled all completion settings will be ignored. | |
175 | set_config('enablecompletion', COMPLETION_ENABLED); | |
176 | ||
177 | // Enable forum RSS feeds. | |
178 | set_config('enablerssfeeds', 1); | |
179 | set_config('forum_enablerssfeeds', 1); | |
180 | ||
181 | $course = $this->getDataGenerator()->create_course(array('numsections'=>1, 'enablecompletion' => COMPLETION_ENABLED), | |
182 | array('createsections'=>true)); | |
183 | ||
184 | $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id)); | |
dd5d933f | 185 | |
7cb0ea2c | 186 | // Create assign module instance for test. |
7bf4f6e9 JM |
187 | $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); |
188 | $params['course'] = $course->id; | |
189 | $instance = $generator->create_instance($params); | |
190 | $assigncm = get_coursemodule_from_instance('assign', $instance->id); | |
dd5d933f | 191 | |
7bf4f6e9 JM |
192 | // Module test values. |
193 | $moduleinfo = new stdClass(); | |
dd5d933f | 194 | |
7bf4f6e9 JM |
195 | // Always mandatory generic values to any module. |
196 | $moduleinfo->modulename = $modulename; | |
197 | $moduleinfo->section = 1; // This is the section number in the course. Not the section id in the database. | |
198 | $moduleinfo->course = $course->id; | |
199 | $moduleinfo->groupingid = $grouping->id; | |
200 | $moduleinfo->groupmembersonly = 0; | |
201 | $moduleinfo->visible = true; | |
202 | ||
203 | // Sometimes optional generic values for some modules. | |
204 | $moduleinfo->name = 'My test module'; | |
205 | $moduleinfo->showdescription = 1; // standard boolean | |
206 | require_once($CFG->libdir . '/gradelib.php'); | |
207 | $gradecats = grade_get_categories_menu($moduleinfo->course, false); | |
208 | $gradecatid = current(array_keys($gradecats)); // Retrieve the first key of $gradecats | |
209 | $moduleinfo->gradecat = $gradecatid; | |
210 | $moduleinfo->groupmode = VISIBLEGROUPS; | |
211 | $moduleinfo->cmidnumber = 'idnumber_XXX'; | |
212 | ||
213 | // Completion common to all module. | |
214 | $moduleinfo->completion = COMPLETION_TRACKING_AUTOMATIC; | |
215 | $moduleinfo->completionview = COMPLETION_VIEW_REQUIRED; | |
7cb0ea2c | 216 | $moduleinfo->completiongradeitemnumber = 1; |
7bf4f6e9 JM |
217 | $moduleinfo->completionexpected = time() + (7 * 24 * 3600); |
218 | ||
219 | // Conditional activity. | |
220 | $moduleinfo->availablefrom = time(); | |
221 | $moduleinfo->availableuntil = time() + (7 * 24 * 3600); | |
222 | $moduleinfo->showavailability = CONDITION_STUDENTVIEW_SHOW; | |
223 | $coursegradeitem = grade_item::fetch_course_item($moduleinfo->course); //the activity will become available only when the user reach some grade into the course itself. | |
224 | $moduleinfo->conditiongradegroup = array(array('conditiongradeitemid' => $coursegradeitem->id, 'conditiongrademin' => 10, 'conditiongrademax' => 80)); | |
225 | $moduleinfo->conditionfieldgroup = array(array('conditionfield' => 'email', 'conditionfieldoperator' => OP_CONTAINS, 'conditionfieldvalue' => '@')); | |
226 | $moduleinfo->conditioncompletiongroup = array(array('conditionsourcecmid' => $assigncm->id, 'conditionrequiredcompletion' => COMPLETION_COMPLETE)); // "conditionsourcecmid == 0" => none | |
227 | ||
228 | // Grading and Advanced grading. | |
229 | require_once($CFG->dirroot . '/rating/lib.php'); | |
230 | $moduleinfo->assessed = RATING_AGGREGATE_AVERAGE; | |
231 | $moduleinfo->scale = 10; // Note: it could be minus (for specific course scale). It is a signed number. | |
232 | $moduleinfo->assesstimestart = time(); | |
233 | $moduleinfo->assesstimefinish = time() + (7 * 24 * 3600); | |
234 | ||
7cb0ea2c | 235 | // RSS. |
7bf4f6e9 JM |
236 | $moduleinfo->rsstype = 2; |
237 | $moduleinfo->rssarticles = 10; | |
238 | ||
239 | // Optional intro editor (depends of module). | |
7bf4f6e9 JM |
240 | $draftid_editor = 0; |
241 | file_prepare_draft_area($draftid_editor, null, null, null, null); | |
242 | $moduleinfo->introeditor = array('text' => 'This is a module', 'format' => FORMAT_HTML, 'itemid' => $draftid_editor); | |
dd5d933f | 243 | |
7bf4f6e9 JM |
244 | // Following is the advanced grading method area called 'submissions' for the 'assign' module. |
245 | if (plugin_supports('mod', $modulename, FEATURE_GRADE_HAS_GRADE, false) && !plugin_supports('mod', $modulename, FEATURE_RATE, false)) { | |
246 | $moduleinfo->grade = 100; | |
247 | } | |
7cb0ea2c | 248 | |
7bf4f6e9 JM |
249 | // Plagiarism form values. |
250 | // No plagiarism plugin installed by default. Use this space to make your own test. | |
251 | ||
252 | // Values specific to the module. | |
253 | $modulesetvalues = $modulename.'_create_set_values'; | |
254 | $this->$modulesetvalues($moduleinfo); | |
255 | ||
256 | // Create the module. | |
257 | $result = create_module($moduleinfo); | |
258 | ||
259 | // Retrieve the module info. | |
260 | $dbmodinstance = $DB->get_record($moduleinfo->modulename, array('id' => $result->instance)); | |
261 | $dbcm = get_coursemodule_from_instance($moduleinfo->modulename, $result->instance); | |
262 | // We passed the course section number to create_courses but $dbcm contain the section id. | |
263 | // We need to retrieve the db course section number. | |
264 | $section = $DB->get_record('course_sections', array('course' => $dbcm->course, 'id' => $dbcm->section)); | |
7cb0ea2c | 265 | // Retrieve the grade item. |
7bf4f6e9 JM |
266 | $gradeitem = $DB->get_record('grade_items', array('courseid' => $moduleinfo->course, |
267 | 'iteminstance' => $dbmodinstance->id, 'itemmodule' => $moduleinfo->modulename)); | |
268 | ||
269 | // Compare the values common to all module instances. | |
270 | $this->assertEquals($moduleinfo->modulename, $dbcm->modname); | |
271 | $this->assertEquals($moduleinfo->section, $section->section); | |
272 | $this->assertEquals($moduleinfo->course, $dbcm->course); | |
273 | $this->assertEquals($moduleinfo->groupingid, $dbcm->groupingid); | |
274 | $this->assertEquals($moduleinfo->groupmembersonly, $dbcm->groupmembersonly); | |
275 | $this->assertEquals($moduleinfo->visible, $dbcm->visible); | |
276 | $this->assertEquals($moduleinfo->completion, $dbcm->completion); | |
277 | $this->assertEquals($moduleinfo->completionview, $dbcm->completionview); | |
278 | $this->assertEquals($moduleinfo->completiongradeitemnumber, $dbcm->completiongradeitemnumber); | |
279 | $this->assertEquals($moduleinfo->completionexpected, $dbcm->completionexpected); | |
280 | $this->assertEquals($moduleinfo->availablefrom, $dbcm->availablefrom); | |
281 | $this->assertEquals($moduleinfo->availableuntil, $dbcm->availableuntil); | |
282 | $this->assertEquals($moduleinfo->showavailability, $dbcm->showavailability); | |
283 | $this->assertEquals($moduleinfo->showdescription, $dbcm->showdescription); | |
284 | $this->assertEquals($moduleinfo->groupmode, $dbcm->groupmode); | |
285 | $this->assertEquals($moduleinfo->cmidnumber, $dbcm->idnumber); | |
286 | $this->assertEquals($moduleinfo->gradecat, $gradeitem->categoryid); | |
287 | ||
288 | // Optional grade testing. | |
289 | if (plugin_supports('mod', $modulename, FEATURE_GRADE_HAS_GRADE, false) && !plugin_supports('mod', $modulename, FEATURE_RATE, false)) { | |
290 | $this->assertEquals($moduleinfo->grade, $dbmodinstance->grade); | |
291 | } | |
292 | ||
293 | // Some optional (but quite common) to some module. | |
294 | $this->assertEquals($moduleinfo->name, $dbmodinstance->name); | |
295 | $this->assertEquals($moduleinfo->intro, $dbmodinstance->intro); | |
296 | $this->assertEquals($moduleinfo->introformat, $dbmodinstance->introformat); | |
297 | ||
298 | // Common values when conditional activity is enabled. | |
299 | foreach ($moduleinfo->conditionfieldgroup as $fieldgroup) { | |
300 | $isfieldgroupsaved = $DB->count_records('course_modules_avail_fields', array('coursemoduleid' => $dbcm->id, | |
301 | 'userfield' => $fieldgroup['conditionfield'], 'operator' => $fieldgroup['conditionfieldoperator'], | |
302 | 'value' => $fieldgroup['conditionfieldvalue'])); | |
303 | $this->assertEquals(1, $isfieldgroupsaved); | |
304 | } | |
305 | foreach ($moduleinfo->conditiongradegroup as $gradegroup) { | |
306 | $isgradegroupsaved = $DB->count_records('course_modules_availability', array('coursemoduleid' => $dbcm->id, | |
307 | 'grademin' => $gradegroup['conditiongrademin'], 'grademax' => $gradegroup['conditiongrademax'], | |
308 | 'gradeitemid' => $gradegroup['conditiongradeitemid'])); | |
309 | $this->assertEquals(1, $isgradegroupsaved); | |
310 | } | |
311 | foreach ($moduleinfo->conditioncompletiongroup as $completiongroup) { | |
312 | $iscompletiongroupsaved = $DB->count_records('course_modules_availability', array('coursemoduleid' => $dbcm->id, | |
313 | 'sourcecmid' => $completiongroup['conditionsourcecmid'], 'requiredcompletion' => $completiongroup['conditionrequiredcompletion'])); | |
314 | $this->assertEquals(1, $iscompletiongroupsaved); | |
315 | } | |
316 | ||
7cb0ea2c | 317 | // Test specific to the module. |
7bf4f6e9 JM |
318 | $modulerunasserts = $modulename.'_create_run_asserts'; |
319 | $this->$modulerunasserts($moduleinfo, $dbmodinstance); | |
7bf4f6e9 | 320 | } |
dd5d933f | 321 | |
7bf4f6e9 JM |
322 | /** |
323 | * Test create_module() for multiple modules defined in the $modules array (first declaration of the function). | |
324 | */ | |
325 | public function test_create_module() { | |
326 | // Add the module name you want to test here. | |
7cb0ea2c | 327 | // Create the match MODULENAME_create_set_values() and MODULENAME_create_run_asserts(). |
7bf4f6e9 JM |
328 | $modules = array('forum', 'assign'); |
329 | // Run all tests. | |
330 | foreach ($modules as $modulename) { | |
331 | $this->create_specific_module_test($modulename); | |
332 | } | |
dd5d933f JM |
333 | } |
334 | ||
335 | /** | |
7bf4f6e9 | 336 | * Test update_module() for multiple modules defined in the $modules array (first declaration of the function). |
dd5d933f JM |
337 | */ |
338 | public function test_update_module() { | |
7bf4f6e9 | 339 | // Add the module name you want to test here. |
7cb0ea2c | 340 | // Create the match MODULENAME_update_set_values() and MODULENAME_update_run_asserts(). |
7bf4f6e9 JM |
341 | $modules = array('forum'); |
342 | // Run all tests. | |
343 | foreach ($modules as $modulename) { | |
344 | $this->update_specific_module_test($modulename); | |
345 | } | |
346 | } | |
347 | ||
348 | /** | |
349 | * Set forum specific test values for calling update_module(). | |
350 | * | |
351 | * @param object $moduleinfo - the moduleinfo to add some specific values - passed in reference. | |
352 | */ | |
353 | private function forum_update_set_values(&$moduleinfo) { | |
354 | // Completion specific to forum - optional. | |
355 | $moduleinfo->completionposts = 3; | |
356 | $moduleinfo->completiondiscussions = 1; | |
357 | $moduleinfo->completionreplies = 2; | |
358 | ||
7cb0ea2c | 359 | // Specific values to the Forum module. |
7bf4f6e9 JM |
360 | $moduleinfo->forcesubscribe = FORUM_INITIALSUBSCRIBE; |
361 | $moduleinfo->type = 'single'; | |
362 | $moduleinfo->trackingtype = FORUM_TRACKING_ON; | |
363 | $moduleinfo->maxbytes = 10240; | |
364 | $moduleinfo->maxattachments = 2; | |
365 | ||
7cb0ea2c | 366 | // Post threshold for blocking - specific to forum. |
7bf4f6e9 JM |
367 | $moduleinfo->blockperiod = 60*60*24; |
368 | $moduleinfo->blockafter = 10; | |
369 | $moduleinfo->warnafter = 5; | |
370 | } | |
371 | ||
372 | /** | |
373 | * Execute test asserts on the saved DB data by update_module($forum). | |
374 | * | |
375 | * @param object $moduleinfo - the specific forum values that were used to update a forum. | |
376 | * @param object $dbmodinstance - the DB values of the updated forum. | |
377 | */ | |
378 | private function forum_update_run_asserts($moduleinfo, $dbmodinstance) { | |
379 | // Compare values specific to forums. | |
380 | $this->assertEquals($moduleinfo->forcesubscribe, $dbmodinstance->forcesubscribe); | |
381 | $this->assertEquals($moduleinfo->type, $dbmodinstance->type); | |
382 | $this->assertEquals($moduleinfo->assessed, $dbmodinstance->assessed); | |
383 | $this->assertEquals($moduleinfo->completionposts, $dbmodinstance->completionposts); | |
384 | $this->assertEquals($moduleinfo->completiondiscussions, $dbmodinstance->completiondiscussions); | |
385 | $this->assertEquals($moduleinfo->completionreplies, $dbmodinstance->completionreplies); | |
386 | $this->assertEquals($moduleinfo->scale, $dbmodinstance->scale); | |
387 | $this->assertEquals($moduleinfo->assesstimestart, $dbmodinstance->assesstimestart); | |
388 | $this->assertEquals($moduleinfo->assesstimefinish, $dbmodinstance->assesstimefinish); | |
389 | $this->assertEquals($moduleinfo->rsstype, $dbmodinstance->rsstype); | |
390 | $this->assertEquals($moduleinfo->rssarticles, $dbmodinstance->rssarticles); | |
391 | $this->assertEquals($moduleinfo->trackingtype, $dbmodinstance->trackingtype); | |
392 | $this->assertEquals($moduleinfo->maxbytes, $dbmodinstance->maxbytes); | |
393 | $this->assertEquals($moduleinfo->maxattachments, $dbmodinstance->maxattachments); | |
394 | $this->assertEquals($moduleinfo->blockperiod, $dbmodinstance->blockperiod); | |
395 | $this->assertEquals($moduleinfo->blockafter, $dbmodinstance->blockafter); | |
396 | $this->assertEquals($moduleinfo->warnafter, $dbmodinstance->warnafter); | |
397 | } | |
398 | ||
399 | ||
400 | ||
401 | /** | |
402 | * Test a specific type of module. | |
403 | * | |
404 | * @param string $modulename - the module name to test | |
405 | */ | |
406 | private function update_specific_module_test($modulename) { | |
dd5d933f JM |
407 | global $DB, $CFG; |
408 | ||
409 | $this->resetAfterTest(true); | |
410 | ||
411 | $this->setAdminUser(); | |
412 | ||
7bf4f6e9 JM |
413 | // Warnings: you'll need to change this line if ever you come to test a module not following Moodle standard. |
414 | require_once($CFG->dirroot.'/mod/'. $modulename .'/lib.php'); | |
dd5d933f | 415 | |
7bf4f6e9 JM |
416 | // Enable avaibility. |
417 | // If not enabled all conditional fields will be ignored. | |
418 | set_config('enableavailability', 1); | |
419 | ||
420 | // Enable course completion. | |
421 | // If not enabled all completion settings will be ignored. | |
422 | set_config('enablecompletion', COMPLETION_ENABLED); | |
423 | ||
424 | // Enable forum RSS feeds. | |
425 | set_config('enablerssfeeds', 1); | |
426 | set_config('forum_enablerssfeeds', 1); | |
427 | ||
428 | $course = $this->getDataGenerator()->create_course(array('numsections'=>1, 'enablecompletion' => COMPLETION_ENABLED), | |
dd5d933f JM |
429 | array('createsections'=>true)); |
430 | ||
431 | $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id)); | |
432 | ||
7cb0ea2c | 433 | // Create assign module instance for testing gradeitem. |
7bf4f6e9 JM |
434 | $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); |
435 | $params['course'] = $course->id; | |
436 | $instance = $generator->create_instance($params); | |
437 | $assigncm = get_coursemodule_from_instance('assign', $instance->id); | |
dd5d933f | 438 | |
7cb0ea2c | 439 | // Create the test forum to update. |
7bf4f6e9 JM |
440 | $initvalues = new stdClass(); |
441 | $initvalues->introformat = FORMAT_HTML; | |
442 | $initvalues->course = $course->id; | |
443 | $forum = self::getDataGenerator()->create_module('forum', $initvalues); | |
dd5d933f | 444 | |
7cb0ea2c | 445 | // Retrieve course module. |
7bf4f6e9 | 446 | $cm = get_coursemodule_from_instance('forum', $forum->id); |
dd5d933f | 447 | |
7bf4f6e9 | 448 | // Module test values. |
dd5d933f JM |
449 | $moduleinfo = new stdClass(); |
450 | ||
7bf4f6e9 | 451 | // Always mandatory generic values to any module. |
dd5d933f | 452 | $moduleinfo->coursemodule = $cm->id; |
7bf4f6e9 JM |
453 | $moduleinfo->modulename = $modulename; |
454 | $moduleinfo->course = $course->id; | |
455 | $moduleinfo->groupingid = $grouping->id; | |
456 | $moduleinfo->groupmembersonly = 0; | |
457 | $moduleinfo->visible = true; | |
458 | ||
459 | // Sometimes optional generic values for some modules. | |
460 | $moduleinfo->name = 'My test module'; | |
461 | $moduleinfo->showdescription = 1; // standard boolean | |
462 | require_once($CFG->libdir . '/gradelib.php'); | |
463 | $gradecats = grade_get_categories_menu($moduleinfo->course, false); | |
464 | $gradecatid = current(array_keys($gradecats)); // Retrieve the first key of $gradecats | |
465 | $moduleinfo->gradecat = $gradecatid; | |
466 | $moduleinfo->groupmode = VISIBLEGROUPS; | |
467 | $moduleinfo->cmidnumber = 'idnumber_XXX'; | |
468 | ||
469 | // Completion common to all module. | |
470 | $moduleinfo->completion = COMPLETION_TRACKING_AUTOMATIC; | |
471 | $moduleinfo->completionview = COMPLETION_VIEW_REQUIRED; | |
7cb0ea2c | 472 | $moduleinfo->completiongradeitemnumber = 1; |
7bf4f6e9 | 473 | $moduleinfo->completionexpected = time() + (7 * 24 * 3600); |
69a0e65c | 474 | $moduleinfo->completionunlocked = 1; |
7bf4f6e9 JM |
475 | |
476 | // Conditional activity. | |
477 | $moduleinfo->availablefrom = time(); | |
478 | $moduleinfo->availableuntil = time() + (7 * 24 * 3600); | |
479 | $moduleinfo->showavailability = CONDITION_STUDENTVIEW_SHOW; | |
480 | $coursegradeitem = grade_item::fetch_course_item($moduleinfo->course); //the activity will become available only when the user reach some grade into the course itself. | |
481 | $moduleinfo->conditiongradegroup = array(array('conditiongradeitemid' => $coursegradeitem->id, 'conditiongrademin' => 10, 'conditiongrademax' => 80)); | |
482 | $moduleinfo->conditionfieldgroup = array(array('conditionfield' => 'email', 'conditionfieldoperator' => OP_CONTAINS, 'conditionfieldvalue' => '@')); | |
483 | $moduleinfo->conditioncompletiongroup = array(array('conditionsourcecmid' => $assigncm->id, 'conditionrequiredcompletion' => COMPLETION_COMPLETE)); // "conditionsourcecmid == 0" => none | |
484 | ||
485 | // Grading and Advanced grading. | |
486 | require_once($CFG->dirroot . '/rating/lib.php'); | |
487 | $moduleinfo->assessed = RATING_AGGREGATE_AVERAGE; | |
488 | $moduleinfo->scale = 10; // Note: it could be minus (for specific course scale). It is a signed number. | |
489 | $moduleinfo->assesstimestart = time(); | |
490 | $moduleinfo->assesstimefinish = time() + (7 * 24 * 3600); | |
491 | ||
7cb0ea2c | 492 | // RSS. |
7bf4f6e9 JM |
493 | $moduleinfo->rsstype = 2; |
494 | $moduleinfo->rssarticles = 10; | |
495 | ||
496 | // Optional intro editor (depends of module). | |
dd5d933f JM |
497 | $draftid_editor = 0; |
498 | file_prepare_draft_area($draftid_editor, null, null, null, null); | |
7bf4f6e9 | 499 | $moduleinfo->introeditor = array('text' => 'This is a module', 'format' => FORMAT_HTML, 'itemid' => $draftid_editor); |
dd5d933f | 500 | |
7bf4f6e9 JM |
501 | // Following is the advanced grading method area called 'submissions' for the 'assign' module. |
502 | if (plugin_supports('mod', $modulename, FEATURE_GRADE_HAS_GRADE, false) && !plugin_supports('mod', $modulename, FEATURE_RATE, false)) { | |
503 | $moduleinfo->grade = 100; | |
504 | } | |
505 | // Plagiarism form values. | |
dd5d933f JM |
506 | // No plagiarism plugin installed by default. Use this space to make your own test. |
507 | ||
7bf4f6e9 JM |
508 | // Values specific to the module. |
509 | $modulesetvalues = $modulename.'_update_set_values'; | |
510 | $this->$modulesetvalues($moduleinfo); | |
511 | ||
512 | // Create the module. | |
513 | $result = update_module($moduleinfo); | |
514 | ||
515 | // Retrieve the module info. | |
516 | $dbmodinstance = $DB->get_record($moduleinfo->modulename, array('id' => $result->instance)); | |
517 | $dbcm = get_coursemodule_from_instance($moduleinfo->modulename, $result->instance); | |
7cb0ea2c | 518 | // Retrieve the grade item. |
7bf4f6e9 JM |
519 | $gradeitem = $DB->get_record('grade_items', array('courseid' => $moduleinfo->course, |
520 | 'iteminstance' => $dbmodinstance->id, 'itemmodule' => $moduleinfo->modulename)); | |
521 | ||
522 | // Compare the values common to all module instances. | |
523 | $this->assertEquals($moduleinfo->modulename, $dbcm->modname); | |
524 | $this->assertEquals($moduleinfo->course, $dbcm->course); | |
525 | $this->assertEquals($moduleinfo->groupingid, $dbcm->groupingid); | |
526 | $this->assertEquals($moduleinfo->groupmembersonly, $dbcm->groupmembersonly); | |
527 | $this->assertEquals($moduleinfo->visible, $dbcm->visible); | |
528 | $this->assertEquals($moduleinfo->completion, $dbcm->completion); | |
529 | $this->assertEquals($moduleinfo->completionview, $dbcm->completionview); | |
530 | $this->assertEquals($moduleinfo->completiongradeitemnumber, $dbcm->completiongradeitemnumber); | |
531 | $this->assertEquals($moduleinfo->completionexpected, $dbcm->completionexpected); | |
532 | $this->assertEquals($moduleinfo->availablefrom, $dbcm->availablefrom); | |
533 | $this->assertEquals($moduleinfo->availableuntil, $dbcm->availableuntil); | |
534 | $this->assertEquals($moduleinfo->showavailability, $dbcm->showavailability); | |
535 | $this->assertEquals($moduleinfo->showdescription, $dbcm->showdescription); | |
536 | $this->assertEquals($moduleinfo->groupmode, $dbcm->groupmode); | |
537 | $this->assertEquals($moduleinfo->cmidnumber, $dbcm->idnumber); | |
538 | $this->assertEquals($moduleinfo->gradecat, $gradeitem->categoryid); | |
539 | ||
540 | // Optional grade testing. | |
541 | if (plugin_supports('mod', $modulename, FEATURE_GRADE_HAS_GRADE, false) && !plugin_supports('mod', $modulename, FEATURE_RATE, false)) { | |
542 | $this->assertEquals($moduleinfo->grade, $dbmodinstance->grade); | |
543 | } | |
544 | ||
545 | // Some optional (but quite common) to some module. | |
546 | $this->assertEquals($moduleinfo->name, $dbmodinstance->name); | |
547 | $this->assertEquals($moduleinfo->intro, $dbmodinstance->intro); | |
548 | $this->assertEquals($moduleinfo->introformat, $dbmodinstance->introformat); | |
549 | ||
550 | // Common values when conditional activity is enabled. | |
551 | foreach ($moduleinfo->conditionfieldgroup as $fieldgroup) { | |
552 | $isfieldgroupsaved = $DB->count_records('course_modules_avail_fields', array('coursemoduleid' => $dbcm->id, | |
553 | 'userfield' => $fieldgroup['conditionfield'], 'operator' => $fieldgroup['conditionfieldoperator'], | |
554 | 'value' => $fieldgroup['conditionfieldvalue'])); | |
555 | $this->assertEquals(1, $isfieldgroupsaved); | |
556 | } | |
557 | foreach ($moduleinfo->conditiongradegroup as $gradegroup) { | |
558 | $isgradegroupsaved = $DB->count_records('course_modules_availability', array('coursemoduleid' => $dbcm->id, | |
559 | 'grademin' => $gradegroup['conditiongrademin'], 'grademax' => $gradegroup['conditiongrademax'], | |
560 | 'gradeitemid' => $gradegroup['conditiongradeitemid'])); | |
561 | $this->assertEquals(1, $isgradegroupsaved); | |
562 | } | |
563 | foreach ($moduleinfo->conditioncompletiongroup as $completiongroup) { | |
564 | $iscompletiongroupsaved = $DB->count_records('course_modules_availability', array('coursemoduleid' => $dbcm->id, | |
565 | 'sourcecmid' => $completiongroup['conditionsourcecmid'], 'requiredcompletion' => $completiongroup['conditionrequiredcompletion'])); | |
566 | $this->assertEquals(1, $iscompletiongroupsaved); | |
567 | } | |
568 | ||
7cb0ea2c | 569 | // Test specific to the module. |
7bf4f6e9 JM |
570 | $modulerunasserts = $modulename.'_update_run_asserts'; |
571 | $this->$modulerunasserts($moduleinfo, $dbmodinstance); | |
572 | } | |
dd5d933f JM |
573 | |
574 | ||
f70bfb84 FM |
575 | public function test_create_course() { |
576 | global $DB; | |
577 | $this->resetAfterTest(true); | |
578 | $defaultcategory = $DB->get_field_select('course_categories', "MIN(id)", "parent=0"); | |
579 | ||
580 | $course = new stdClass(); | |
581 | $course->fullname = 'Apu loves Unit TÉsts'; | |
582 | $course->shortname = 'Spread the lÅve'; | |
583 | $course->idnumber = '123'; | |
584 | $course->summary = 'Awesome!'; | |
585 | $course->summaryformat = FORMAT_PLAIN; | |
586 | $course->format = 'topics'; | |
587 | $course->newsitems = 0; | |
588 | $course->numsections = 5; | |
589 | $course->category = $defaultcategory; | |
97d5e39c | 590 | $original = (array) $course; |
f70bfb84 FM |
591 | |
592 | $created = create_course($course); | |
593 | $context = context_course::instance($created->id); | |
594 | ||
595 | // Compare original and created. | |
f70bfb84 FM |
596 | $this->assertEquals($original, array_intersect_key((array) $created, $original)); |
597 | ||
598 | // Ensure default section is created. | |
599 | $sectioncreated = $DB->record_exists('course_sections', array('course' => $created->id, 'section' => 0)); | |
600 | $this->assertTrue($sectioncreated); | |
601 | ||
602 | // Ensure blocks have been associated to the course. | |
603 | $blockcount = $DB->count_records('block_instances', array('parentcontextid' => $context->id)); | |
604 | $this->assertGreaterThan(0, $blockcount); | |
605 | } | |
606 | ||
384c3510 MG |
607 | public function test_create_course_with_generator() { |
608 | global $DB; | |
609 | $this->resetAfterTest(true); | |
610 | $course = $this->getDataGenerator()->create_course(); | |
611 | ||
612 | // Ensure default section is created. | |
613 | $sectioncreated = $DB->record_exists('course_sections', array('course' => $course->id, 'section' => 0)); | |
614 | $this->assertTrue($sectioncreated); | |
615 | } | |
616 | ||
617 | public function test_create_course_sections() { | |
618 | global $DB; | |
619 | $this->resetAfterTest(true); | |
620 | ||
621 | $course = $this->getDataGenerator()->create_course( | |
622 | array('shortname' => 'GrowingCourse', | |
623 | 'fullname' => 'Growing Course', | |
624 | 'numsections' => 5), | |
625 | array('createsections' => true)); | |
626 | ||
627 | // Ensure all 6 (0-5) sections were created and modinfo/sectioninfo cache works properly | |
628 | $sectionscreated = array_keys(get_fast_modinfo($course)->get_section_info_all()); | |
629 | $this->assertEquals(range(0, $course->numsections), $sectionscreated); | |
630 | ||
631 | // this will do nothing, section already exists | |
632 | $this->assertFalse(course_create_sections_if_missing($course, $course->numsections)); | |
633 | ||
634 | // this will create new section | |
635 | $this->assertTrue(course_create_sections_if_missing($course, $course->numsections + 1)); | |
636 | ||
637 | // Ensure all 7 (0-6) sections were created and modinfo/sectioninfo cache works properly | |
638 | $sectionscreated = array_keys(get_fast_modinfo($course)->get_section_info_all()); | |
639 | $this->assertEquals(range(0, $course->numsections + 1), $sectionscreated); | |
640 | } | |
641 | ||
5523c344 | 642 | public function test_course_add_cm_to_section() { |
643 | global $DB; | |
644 | $this->resetAfterTest(true); | |
645 | ||
646 | // Create course with 1 section. | |
647 | $course = $this->getDataGenerator()->create_course( | |
648 | array('shortname' => 'GrowingCourse', | |
649 | 'fullname' => 'Growing Course', | |
650 | 'numsections' => 1), | |
651 | array('createsections' => true)); | |
652 | ||
653 | // Trash modinfo. | |
654 | rebuild_course_cache($course->id, true); | |
655 | ||
656 | // Create some cms for testing. | |
657 | $cmids = array(); | |
658 | for ($i=0; $i<4; $i++) { | |
659 | $cmids[$i] = $DB->insert_record('course_modules', array('course' => $course->id)); | |
660 | } | |
661 | ||
662 | // Add it to section that exists. | |
663 | course_add_cm_to_section($course, $cmids[0], 1); | |
664 | ||
665 | // Check it got added to sequence. | |
666 | $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 1)); | |
667 | $this->assertEquals($cmids[0], $sequence); | |
668 | ||
669 | // Add a second, this time using courseid variant of parameters. | |
670 | course_add_cm_to_section($course->id, $cmids[1], 1); | |
671 | $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 1)); | |
672 | $this->assertEquals($cmids[0] . ',' . $cmids[1], $sequence); | |
673 | ||
674 | // Check modinfo was not rebuilt (important for performance if calling | |
675 | // repeatedly). | |
676 | $this->assertNull($DB->get_field('course', 'modinfo', array('id' => $course->id))); | |
677 | ||
678 | // Add one to section that doesn't exist (this might rebuild modinfo). | |
679 | course_add_cm_to_section($course, $cmids[2], 2); | |
680 | $this->assertEquals(3, $DB->count_records('course_sections', array('course' => $course->id))); | |
681 | $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 2)); | |
682 | $this->assertEquals($cmids[2], $sequence); | |
683 | ||
684 | // Add using the 'before' option. | |
685 | course_add_cm_to_section($course, $cmids[3], 2, $cmids[2]); | |
686 | $this->assertEquals(3, $DB->count_records('course_sections', array('course' => $course->id))); | |
687 | $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 2)); | |
688 | $this->assertEquals($cmids[3] . ',' . $cmids[2], $sequence); | |
689 | } | |
690 | ||
354b214c PS |
691 | public function test_reorder_sections() { |
692 | global $DB; | |
693 | $this->resetAfterTest(true); | |
694 | ||
695 | $this->getDataGenerator()->create_course(array('numsections'=>5), array('createsections'=>true)); | |
696 | $course = $this->getDataGenerator()->create_course(array('numsections'=>10), array('createsections'=>true)); | |
697 | $oldsections = array(); | |
698 | $sections = array(); | |
3a222db2 | 699 | foreach ($DB->get_records('course_sections', array('course'=>$course->id), 'id') as $section) { |
354b214c PS |
700 | $oldsections[$section->section] = $section->id; |
701 | $sections[$section->id] = $section->section; | |
702 | } | |
703 | ksort($oldsections); | |
704 | ||
705 | $neworder = reorder_sections($sections, 2, 4); | |
706 | $neworder = array_keys($neworder); | |
707 | $this->assertEquals($oldsections[0], $neworder[0]); | |
708 | $this->assertEquals($oldsections[1], $neworder[1]); | |
709 | $this->assertEquals($oldsections[2], $neworder[4]); | |
710 | $this->assertEquals($oldsections[3], $neworder[2]); | |
711 | $this->assertEquals($oldsections[4], $neworder[3]); | |
712 | $this->assertEquals($oldsections[5], $neworder[5]); | |
713 | $this->assertEquals($oldsections[6], $neworder[6]); | |
714 | ||
eb01aa2c RT |
715 | $neworder = reorder_sections($sections, 4, 2); |
716 | $neworder = array_keys($neworder); | |
717 | $this->assertEquals($oldsections[0], $neworder[0]); | |
718 | $this->assertEquals($oldsections[1], $neworder[1]); | |
719 | $this->assertEquals($oldsections[2], $neworder[3]); | |
720 | $this->assertEquals($oldsections[3], $neworder[4]); | |
721 | $this->assertEquals($oldsections[4], $neworder[2]); | |
722 | $this->assertEquals($oldsections[5], $neworder[5]); | |
723 | $this->assertEquals($oldsections[6], $neworder[6]); | |
724 | ||
354b214c PS |
725 | $neworder = reorder_sections(1, 2, 4); |
726 | $this->assertFalse($neworder); | |
727 | } | |
728 | ||
3d8fe482 | 729 | public function test_move_section_down() { |
354b214c PS |
730 | global $DB; |
731 | $this->resetAfterTest(true); | |
732 | ||
733 | $this->getDataGenerator()->create_course(array('numsections'=>5), array('createsections'=>true)); | |
734 | $course = $this->getDataGenerator()->create_course(array('numsections'=>10), array('createsections'=>true)); | |
735 | $oldsections = array(); | |
736 | foreach ($DB->get_records('course_sections', array('course'=>$course->id)) as $section) { | |
737 | $oldsections[$section->section] = $section->id; | |
738 | } | |
739 | ksort($oldsections); | |
740 | ||
3d8fe482 | 741 | // Test move section down.. |
354b214c PS |
742 | move_section_to($course, 2, 4); |
743 | $sections = array(); | |
744 | foreach ($DB->get_records('course_sections', array('course'=>$course->id)) as $section) { | |
745 | $sections[$section->section] = $section->id; | |
746 | } | |
747 | ksort($sections); | |
748 | ||
749 | $this->assertEquals($oldsections[0], $sections[0]); | |
750 | $this->assertEquals($oldsections[1], $sections[1]); | |
751 | $this->assertEquals($oldsections[2], $sections[4]); | |
752 | $this->assertEquals($oldsections[3], $sections[2]); | |
753 | $this->assertEquals($oldsections[4], $sections[3]); | |
754 | $this->assertEquals($oldsections[5], $sections[5]); | |
755 | $this->assertEquals($oldsections[6], $sections[6]); | |
756 | } | |
757 | ||
3d8fe482 DP |
758 | public function test_move_section_up() { |
759 | global $DB; | |
760 | $this->resetAfterTest(true); | |
761 | ||
762 | $this->getDataGenerator()->create_course(array('numsections'=>5), array('createsections'=>true)); | |
763 | $course = $this->getDataGenerator()->create_course(array('numsections'=>10), array('createsections'=>true)); | |
764 | $oldsections = array(); | |
765 | foreach ($DB->get_records('course_sections', array('course'=>$course->id)) as $section) { | |
766 | $oldsections[$section->section] = $section->id; | |
767 | } | |
768 | ksort($oldsections); | |
769 | ||
770 | // Test move section up.. | |
771 | move_section_to($course, 6, 4); | |
772 | $sections = array(); | |
773 | foreach ($DB->get_records('course_sections', array('course'=>$course->id)) as $section) { | |
774 | $sections[$section->section] = $section->id; | |
775 | } | |
776 | ksort($sections); | |
777 | ||
778 | $this->assertEquals($oldsections[0], $sections[0]); | |
779 | $this->assertEquals($oldsections[1], $sections[1]); | |
780 | $this->assertEquals($oldsections[2], $sections[2]); | |
781 | $this->assertEquals($oldsections[3], $sections[3]); | |
782 | $this->assertEquals($oldsections[4], $sections[5]); | |
783 | $this->assertEquals($oldsections[5], $sections[6]); | |
784 | $this->assertEquals($oldsections[6], $sections[4]); | |
785 | } | |
786 | ||
787 | public function test_move_section_marker() { | |
788 | global $DB; | |
789 | $this->resetAfterTest(true); | |
790 | ||
791 | $this->getDataGenerator()->create_course(array('numsections'=>5), array('createsections'=>true)); | |
792 | $course = $this->getDataGenerator()->create_course(array('numsections'=>10), array('createsections'=>true)); | |
793 | ||
794 | // Set course marker to the section we are going to move.. | |
795 | course_set_marker($course->id, 2); | |
796 | // Verify that the course marker is set correctly. | |
797 | $course = $DB->get_record('course', array('id' => $course->id)); | |
798 | $this->assertEquals(2, $course->marker); | |
799 | ||
800 | // Test move the marked section down.. | |
801 | move_section_to($course, 2, 4); | |
802 | ||
803 | // Verify that the coruse marker has been moved along with the section.. | |
804 | $course = $DB->get_record('course', array('id' => $course->id)); | |
805 | $this->assertEquals(4, $course->marker); | |
806 | ||
807 | // Test move the marked section up.. | |
808 | move_section_to($course, 4, 3); | |
809 | ||
810 | // Verify that the course marker has been moved along with the section.. | |
811 | $course = $DB->get_record('course', array('id' => $course->id)); | |
812 | $this->assertEquals(3, $course->marker); | |
813 | ||
814 | // Test moving a non-marked section above the marked section.. | |
815 | move_section_to($course, 4, 2); | |
816 | ||
817 | // Verify that the course marker has been moved down to accomodate.. | |
818 | $course = $DB->get_record('course', array('id' => $course->id)); | |
819 | $this->assertEquals(4, $course->marker); | |
820 | ||
821 | // Test moving a non-marked section below the marked section.. | |
822 | move_section_to($course, 3, 6); | |
823 | ||
824 | // Verify that the course marker has been up to accomodate.. | |
825 | $course = $DB->get_record('course', array('id' => $course->id)); | |
826 | $this->assertEquals(3, $course->marker); | |
827 | } | |
828 | ||
354b214c PS |
829 | public function test_get_course_display_name_for_list() { |
830 | global $CFG; | |
831 | $this->resetAfterTest(true); | |
832 | ||
833 | $course = $this->getDataGenerator()->create_course(array('shortname' => 'FROG101', 'fullname' => 'Introduction to pond life')); | |
834 | ||
835 | $CFG->courselistshortnames = 0; | |
836 | $this->assertEquals('Introduction to pond life', get_course_display_name_for_list($course)); | |
837 | ||
838 | $CFG->courselistshortnames = 1; | |
839 | $this->assertEquals('FROG101 Introduction to pond life', get_course_display_name_for_list($course)); | |
840 | } | |
b1a8aa73 | 841 | |
384c3510 | 842 | public function test_move_module_in_course() { |
3f61e4cb ARN |
843 | global $DB; |
844 | ||
384c3510 MG |
845 | $this->resetAfterTest(true); |
846 | // Setup fixture | |
3f61e4cb | 847 | $course = $this->getDataGenerator()->create_course(array('numsections'=>5), array('createsections' => true)); |
384c3510 MG |
848 | $forum = $this->getDataGenerator()->create_module('forum', array('course'=>$course->id)); |
849 | ||
384c3510 MG |
850 | $cms = get_fast_modinfo($course)->get_cms(); |
851 | $cm = reset($cms); | |
852 | ||
3f61e4cb ARN |
853 | $newsection = get_fast_modinfo($course)->get_section_info(3); |
854 | $oldsectionid = $cm->section; | |
855 | ||
856 | // Perform the move | |
857 | moveto_module($cm, $newsection); | |
384c3510 | 858 | |
3f61e4cb ARN |
859 | $cms = get_fast_modinfo($course)->get_cms(); |
860 | $cm = reset($cms); | |
384c3510 | 861 | |
3f61e4cb | 862 | // Check that the cached modinfo contains the correct section info |
384c3510 MG |
863 | $modinfo = get_fast_modinfo($course); |
864 | $this->assertTrue(empty($modinfo->sections[0])); | |
865 | $this->assertFalse(empty($modinfo->sections[3])); | |
3f61e4cb ARN |
866 | |
867 | // Check that the old section's sequence no longer contains this ID | |
868 | $oldsection = $DB->get_record('course_sections', array('id' => $oldsectionid)); | |
869 | $oldsequences = explode(',', $newsection->sequence); | |
870 | $this->assertFalse(in_array($cm->id, $oldsequences)); | |
871 | ||
872 | // Check that the new section's sequence now contains this ID | |
873 | $newsection = $DB->get_record('course_sections', array('id' => $newsection->id)); | |
874 | $newsequences = explode(',', $newsection->sequence); | |
875 | $this->assertTrue(in_array($cm->id, $newsequences)); | |
876 | ||
877 | // Check that the section number has been changed in the cm | |
878 | $this->assertEquals($newsection->id, $cm->section); | |
879 | ||
880 | ||
881 | // Perform a second move as some issues were only seen on the second move | |
882 | $newsection = get_fast_modinfo($course)->get_section_info(2); | |
883 | $oldsectionid = $cm->section; | |
884 | $result = moveto_module($cm, $newsection); | |
885 | $this->assertTrue($result); | |
886 | ||
3f61e4cb ARN |
887 | $cms = get_fast_modinfo($course)->get_cms(); |
888 | $cm = reset($cms); | |
889 | ||
890 | // Check that the cached modinfo contains the correct section info | |
891 | $modinfo = get_fast_modinfo($course); | |
892 | $this->assertTrue(empty($modinfo->sections[0])); | |
893 | $this->assertFalse(empty($modinfo->sections[2])); | |
894 | ||
895 | // Check that the old section's sequence no longer contains this ID | |
896 | $oldsection = $DB->get_record('course_sections', array('id' => $oldsectionid)); | |
897 | $oldsequences = explode(',', $newsection->sequence); | |
898 | $this->assertFalse(in_array($cm->id, $oldsequences)); | |
899 | ||
900 | // Check that the new section's sequence now contains this ID | |
901 | $newsection = $DB->get_record('course_sections', array('id' => $newsection->id)); | |
902 | $newsequences = explode(',', $newsection->sequence); | |
903 | $this->assertTrue(in_array($cm->id, $newsequences)); | |
384c3510 | 904 | } |
f7d6e650 FM |
905 | |
906 | public function test_module_visibility() { | |
907 | $this->setAdminUser(); | |
908 | $this->resetAfterTest(true); | |
909 | ||
910 | // Create course and modules. | |
911 | $course = $this->getDataGenerator()->create_course(array('numsections' => 5)); | |
912 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); | |
913 | $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), 'course' => $course->id)); | |
914 | $modules = compact('forum', 'assign'); | |
915 | ||
916 | // Hiding the modules. | |
917 | foreach ($modules as $mod) { | |
918 | set_coursemodule_visible($mod->cmid, 0); | |
919 | $this->check_module_visibility($mod, 0, 0); | |
920 | } | |
921 | ||
922 | // Showing the modules. | |
923 | foreach ($modules as $mod) { | |
924 | set_coursemodule_visible($mod->cmid, 1); | |
925 | $this->check_module_visibility($mod, 1, 1); | |
926 | } | |
927 | } | |
928 | ||
929 | public function test_section_visibility() { | |
930 | $this->setAdminUser(); | |
931 | $this->resetAfterTest(true); | |
932 | ||
933 | // Create course. | |
934 | $course = $this->getDataGenerator()->create_course(array('numsections' => 3), array('createsections' => true)); | |
935 | ||
936 | // Testing an empty section. | |
937 | $sectionnumber = 1; | |
938 | set_section_visible($course->id, $sectionnumber, 0); | |
939 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
940 | $this->assertEquals($section_info->visible, 0); | |
941 | set_section_visible($course->id, $sectionnumber, 1); | |
942 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
943 | $this->assertEquals($section_info->visible, 1); | |
944 | ||
945 | // Testing a section with visible modules. | |
946 | $sectionnumber = 2; | |
947 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id), | |
948 | array('section' => $sectionnumber)); | |
949 | $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), | |
950 | 'course' => $course->id), array('section' => $sectionnumber)); | |
951 | $modules = compact('forum', 'assign'); | |
952 | set_section_visible($course->id, $sectionnumber, 0); | |
953 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
954 | $this->assertEquals($section_info->visible, 0); | |
955 | foreach ($modules as $mod) { | |
956 | $this->check_module_visibility($mod, 0, 1); | |
957 | } | |
958 | set_section_visible($course->id, $sectionnumber, 1); | |
959 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
960 | $this->assertEquals($section_info->visible, 1); | |
961 | foreach ($modules as $mod) { | |
962 | $this->check_module_visibility($mod, 1, 1); | |
963 | } | |
964 | ||
965 | // Testing a section with hidden modules, which should stay hidden. | |
966 | $sectionnumber = 3; | |
967 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id), | |
968 | array('section' => $sectionnumber)); | |
969 | $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), | |
970 | 'course' => $course->id), array('section' => $sectionnumber)); | |
971 | $modules = compact('forum', 'assign'); | |
972 | foreach ($modules as $mod) { | |
973 | set_coursemodule_visible($mod->cmid, 0); | |
974 | $this->check_module_visibility($mod, 0, 0); | |
975 | } | |
976 | set_section_visible($course->id, $sectionnumber, 0); | |
977 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
978 | $this->assertEquals($section_info->visible, 0); | |
979 | foreach ($modules as $mod) { | |
980 | $this->check_module_visibility($mod, 0, 0); | |
981 | } | |
982 | set_section_visible($course->id, $sectionnumber, 1); | |
983 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
984 | $this->assertEquals($section_info->visible, 1); | |
985 | foreach ($modules as $mod) { | |
986 | $this->check_module_visibility($mod, 0, 0); | |
987 | } | |
988 | } | |
989 | ||
990 | /** | |
991 | * Helper function to assert that a module has correctly been made visible, or hidden. | |
992 | * | |
993 | * @param stdClass $mod module information | |
994 | * @param int $visibility the current state of the module | |
995 | * @param int $visibleold the current state of the visibleold property | |
996 | * @return void | |
997 | */ | |
998 | public function check_module_visibility($mod, $visibility, $visibleold) { | |
999 | global $DB; | |
1000 | $cm = get_fast_modinfo($mod->course)->get_cm($mod->cmid); | |
1001 | $this->assertEquals($visibility, $cm->visible); | |
1002 | $this->assertEquals($visibleold, $cm->visibleold); | |
1003 | ||
1004 | // Check the module grade items. | |
1005 | $grade_items = grade_item::fetch_all(array('itemtype' => 'mod', 'itemmodule' => $cm->modname, | |
1006 | 'iteminstance' => $cm->instance, 'courseid' => $cm->course)); | |
1007 | if ($grade_items) { | |
1008 | foreach ($grade_items as $grade_item) { | |
1009 | if ($visibility) { | |
1010 | $this->assertFalse($grade_item->is_hidden(), "$cm->modname grade_item not visible"); | |
1011 | } else { | |
1012 | $this->assertTrue($grade_item->is_hidden(), "$cm->modname grade_item not hidden"); | |
1013 | } | |
1014 | } | |
1015 | } | |
1016 | ||
1017 | // Check the events visibility. | |
1018 | if ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $cm->modname))) { | |
1019 | foreach ($events as $event) { | |
1020 | $calevent = new calendar_event($event); | |
1021 | $this->assertEquals($visibility, $calevent->visible, "$cm->modname calendar_event visibility"); | |
1022 | } | |
1023 | } | |
1024 | } | |
1025 | ||
b7d3bb0f AG |
1026 | public function test_course_page_type_list() { |
1027 | global $DB; | |
1028 | $this->resetAfterTest(true); | |
1029 | ||
1030 | // Create a category. | |
1031 | $category = new stdClass(); | |
1032 | $category->name = 'Test Category'; | |
1033 | ||
1034 | $testcategory = $this->getDataGenerator()->create_category($category); | |
1035 | ||
1036 | // Create a course. | |
1037 | $course = new stdClass(); | |
1038 | $course->fullname = 'Apu loves Unit TÉsts'; | |
1039 | $course->shortname = 'Spread the lÅve'; | |
1040 | $course->idnumber = '123'; | |
1041 | $course->summary = 'Awesome!'; | |
1042 | $course->summaryformat = FORMAT_PLAIN; | |
1043 | $course->format = 'topics'; | |
1044 | $course->newsitems = 0; | |
1045 | $course->numsections = 5; | |
1046 | $course->category = $testcategory->id; | |
1047 | ||
1048 | $testcourse = $this->getDataGenerator()->create_course($course); | |
1049 | ||
1050 | // Create contexts. | |
1051 | $coursecontext = context_course::instance($testcourse->id); | |
1052 | $parentcontext = $coursecontext->get_parent_context(); // Not actually used. | |
1053 | $pagetype = 'page-course-x'; // Not used either. | |
1054 | $pagetypelist = course_page_type_list($pagetype, $parentcontext, $coursecontext); | |
1055 | ||
1056 | // Page type lists for normal courses. | |
1057 | $testpagetypelist1 = array(); | |
1058 | $testpagetypelist1['*'] = 'Any page'; | |
1059 | $testpagetypelist1['course-*'] = 'Any course page'; | |
1060 | $testpagetypelist1['course-view-*'] = 'Any type of course main page'; | |
1061 | ||
1062 | $this->assertEquals($testpagetypelist1, $pagetypelist); | |
1063 | ||
1064 | // Get the context for the front page course. | |
1065 | $sitecoursecontext = context_course::instance(SITEID); | |
1066 | $pagetypelist = course_page_type_list($pagetype, $parentcontext, $sitecoursecontext); | |
1067 | ||
1068 | // Page type list for the front page course. | |
1069 | $testpagetypelist2 = array('*' => 'Any page'); | |
1070 | $this->assertEquals($testpagetypelist2, $pagetypelist); | |
1071 | ||
1072 | // Make sure that providing no current context to the function doesn't result in an error. | |
1073 | // Calls made from generate_page_type_patterns() may provide null values. | |
1074 | $pagetypelist = course_page_type_list($pagetype, null, null); | |
1075 | $this->assertEquals($pagetypelist, $testpagetypelist1); | |
1076 | } | |
bf6b3c7a AA |
1077 | |
1078 | public function test_compare_activities_by_time_desc() { | |
1079 | ||
1080 | // Let's create some test data. | |
1081 | $activitiesivities = array(); | |
1082 | $x = new stdClass(); | |
1083 | $x->timestamp = null; | |
1084 | $activities[] = $x; | |
1085 | ||
1086 | $x = new stdClass(); | |
1087 | $x->timestamp = 1; | |
1088 | $activities[] = $x; | |
1089 | ||
1090 | $x = new stdClass(); | |
1091 | $x->timestamp = 3; | |
1092 | $activities[] = $x; | |
1093 | ||
1094 | $x = new stdClass(); | |
1095 | $x->timestamp = 0; | |
1096 | $activities[] = $x; | |
1097 | ||
1098 | $x = new stdClass(); | |
1099 | $x->timestamp = 5; | |
1100 | $activities[] = $x; | |
1101 | ||
1102 | $x = new stdClass(); | |
1103 | $activities[] = $x; | |
1104 | ||
1105 | $x = new stdClass(); | |
1106 | $x->timestamp = 5; | |
1107 | $activities[] = $x; | |
1108 | ||
1109 | // Do the sorting. | |
1110 | usort($activities, 'compare_activities_by_time_desc'); | |
1111 | ||
1112 | // Let's check the result. | |
1113 | $last = 10; | |
1114 | foreach($activities as $activity) { | |
1115 | if (empty($activity->timestamp)) { | |
1116 | $activity->timestamp = 0; | |
1117 | } | |
1118 | $this->assertLessThanOrEqual($last, $activity->timestamp); | |
1119 | } | |
1120 | } | |
1121 | ||
1122 | public function test_compare_activities_by_time_asc() { | |
1123 | ||
1124 | // Let's create some test data. | |
1125 | $activities = array(); | |
1126 | $x = new stdClass(); | |
1127 | $x->timestamp = null; | |
1128 | $activities[] = $x; | |
1129 | ||
1130 | $x = new stdClass(); | |
1131 | $x->timestamp = 1; | |
1132 | $activities[] = $x; | |
1133 | ||
1134 | $x = new stdClass(); | |
1135 | $x->timestamp = 3; | |
1136 | $activities[] = $x; | |
1137 | ||
1138 | $x = new stdClass(); | |
1139 | $x->timestamp = 0; | |
1140 | $activities[] = $x; | |
1141 | ||
1142 | $x = new stdClass(); | |
1143 | $x->timestamp = 5; | |
1144 | $activities[] = $x; | |
1145 | ||
1146 | $x = new stdClass(); | |
1147 | $activities[] = $x; | |
1148 | ||
1149 | $x = new stdClass(); | |
1150 | $x->timestamp = 5; | |
1151 | $activities[] = $x; | |
1152 | ||
1153 | // Do the sorting. | |
1154 | usort($activities, 'compare_activities_by_time_asc'); | |
1155 | ||
1156 | // Let's check the result. | |
1157 | $last = 0; | |
1158 | foreach($activities as $activity) { | |
1159 | if (empty($activity->timestamp)) { | |
1160 | $activity->timestamp = 0; | |
1161 | } | |
1162 | $this->assertGreaterThanOrEqual($last, $activity->timestamp); | |
1163 | } | |
1164 | } | |
9ab0aece | 1165 | |
1fff1b8c DP |
1166 | /** |
1167 | * Tests moving a module between hidden/visible sections and | |
1168 | * verifies that the course/module visiblity seettings are | |
1169 | * retained. | |
1170 | */ | |
1171 | public function test_moveto_module_between_hidden_sections() { | |
1172 | global $DB; | |
1173 | ||
1174 | $this->resetAfterTest(true); | |
1175 | ||
1176 | $course = $this->getDataGenerator()->create_course(array('numsections' => 4), array('createsections' => true)); | |
1177 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); | |
1178 | $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id)); | |
1179 | $quiz= $this->getDataGenerator()->create_module('quiz', array('course' => $course->id)); | |
1180 | ||
1181 | // Set the page as hidden | |
1182 | set_coursemodule_visible($page->cmid, 0); | |
1183 | ||
1184 | // Set sections 3 as hidden. | |
1185 | set_section_visible($course->id, 3, 0); | |
1186 | ||
1187 | $modinfo = get_fast_modinfo($course); | |
1188 | ||
1189 | $hiddensection = $modinfo->get_section_info(3); | |
1190 | // New section is definitely not visible: | |
1191 | $this->assertEquals($hiddensection->visible, 0); | |
1192 | ||
1193 | $forumcm = $modinfo->cms[$forum->cmid]; | |
1194 | $pagecm = $modinfo->cms[$page->cmid]; | |
1195 | ||
1196 | // Move the forum and the page to a hidden section. | |
1197 | moveto_module($forumcm, $hiddensection); | |
1198 | moveto_module($pagecm, $hiddensection); | |
1199 | ||
1fff1b8c DP |
1200 | $modinfo = get_fast_modinfo($course); |
1201 | ||
1202 | // Verify that forum and page have been moved to the hidden section and quiz has not. | |
1203 | $this->assertContains($forum->cmid, $modinfo->sections[3]); | |
1204 | $this->assertContains($page->cmid, $modinfo->sections[3]); | |
1205 | $this->assertNotContains($quiz->cmid, $modinfo->sections[3]); | |
1206 | ||
1207 | // Verify that forum has been made invisible. | |
1208 | $forumcm = $modinfo->cms[$forum->cmid]; | |
1209 | $this->assertEquals($forumcm->visible, 0); | |
1210 | // Verify that old state has been retained. | |
1211 | $this->assertEquals($forumcm->visibleold, 1); | |
1212 | ||
1213 | // Verify that page has stayed invisible. | |
1214 | $pagecm = $modinfo->cms[$page->cmid]; | |
1215 | $this->assertEquals($pagecm->visible, 0); | |
1216 | // Verify that old state has been retained. | |
1217 | $this->assertEquals($pagecm->visibleold, 0); | |
1218 | ||
1219 | // Verify that quiz has been unaffected. | |
1220 | $quizcm = $modinfo->cms[$quiz->cmid]; | |
1221 | $this->assertEquals($quizcm->visible, 1); | |
1222 | ||
1223 | // Move forum and page back to visible section. | |
1224 | $visiblesection = $modinfo->get_section_info(2); | |
1225 | moveto_module($forumcm, $visiblesection); | |
1226 | moveto_module($pagecm, $visiblesection); | |
1227 | ||
1fff1b8c DP |
1228 | $modinfo = get_fast_modinfo($course); |
1229 | ||
1230 | // Verify that forum has been made visible. | |
1231 | $forumcm = $modinfo->cms[$forum->cmid]; | |
1232 | $this->assertEquals($forumcm->visible, 1); | |
1233 | ||
1234 | // Verify that page has stayed invisible. | |
1235 | $pagecm = $modinfo->cms[$page->cmid]; | |
1236 | $this->assertEquals($pagecm->visible, 0); | |
1237 | ||
1238 | // Move the page in the same section (this is what mod duplicate does_ | |
1239 | moveto_module($pagecm, $visiblesection, $forumcm); | |
1240 | ||
1fff1b8c DP |
1241 | // Verify that the the page is still hidden |
1242 | $modinfo = get_fast_modinfo($course); | |
1243 | $pagecm = $modinfo->cms[$page->cmid]; | |
1244 | $this->assertEquals($pagecm->visible, 0); | |
1245 | } | |
1246 | ||
1247 | /** | |
1248 | * Tests moving a module around in the same section. moveto_module() | |
1249 | * is called this way in modduplicate. | |
1250 | */ | |
1251 | public function test_moveto_module_in_same_section() { | |
1252 | global $DB; | |
1253 | ||
1254 | $this->resetAfterTest(true); | |
1255 | ||
1256 | $course = $this->getDataGenerator()->create_course(array('numsections' => 3), array('createsections' => true)); | |
1257 | $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id)); | |
1258 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); | |
1259 | ||
1260 | // Simulate inconsistent visible/visibleold values (MDL-38713). | |
1261 | $cm = $DB->get_record('course_modules', array('id' => $page->cmid), '*', MUST_EXIST); | |
1262 | $cm->visible = 0; | |
1263 | $cm->visibleold = 1; | |
1264 | $DB->update_record('course_modules', $cm); | |
1265 | ||
1266 | $modinfo = get_fast_modinfo($course); | |
1267 | $forumcm = $modinfo->cms[$forum->cmid]; | |
1268 | $pagecm = $modinfo->cms[$page->cmid]; | |
1269 | ||
1270 | // Verify that page is hidden. | |
1271 | $this->assertEquals($pagecm->visible, 0); | |
1272 | ||
1273 | // Verify section 0 is where all mods added. | |
1274 | $section = $modinfo->get_section_info(0); | |
1275 | $this->assertEquals($section->id, $forumcm->section); | |
1276 | $this->assertEquals($section->id, $pagecm->section); | |
1277 | ||
1278 | ||
1279 | // Move the forum and the page to a hidden section. | |
1280 | moveto_module($pagecm, $section, $forumcm); | |
1281 | ||
1fff1b8c DP |
1282 | // Verify that the the page is still hidden |
1283 | $modinfo = get_fast_modinfo($course); | |
1284 | $pagecm = $modinfo->cms[$page->cmid]; | |
1285 | $this->assertEquals($pagecm->visible, 0); | |
1286 | } | |
e52c1ea6 DP |
1287 | |
1288 | public function test_course_delete_module() { | |
1289 | global $DB; | |
1290 | $this->resetAfterTest(true); | |
1291 | $this->setAdminUser(); | |
1292 | ||
1293 | // Create course and modules. | |
1294 | $course = $this->getDataGenerator()->create_course(array('numsections' => 5)); | |
1295 | ||
1296 | // Generate an assignment with due date (will generate a course event). | |
1297 | $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), 'course' => $course->id)); | |
1298 | ||
1299 | $cm = get_coursemodule_from_instance('assign', $assign->id); | |
1300 | ||
1301 | // Verify context exists. | |
1302 | $this->assertInstanceOf('context_module', context_module::instance($cm->id, IGNORE_MISSING)); | |
1303 | ||
1304 | // Verify event assignment event has been generated. | |
1305 | $eventcount = $DB->count_records('event', array('instance' => $assign->id, 'modulename' => 'assign')); | |
1306 | $this->assertEquals(1, $eventcount); | |
1307 | ||
1308 | // Run delete.. | |
1309 | course_delete_module($cm->id); | |
1310 | ||
1311 | // Verify the context has been removed. | |
1312 | $this->assertFalse(context_module::instance($cm->id, IGNORE_MISSING)); | |
1313 | ||
1314 | // Verify the course_module record has been deleted. | |
1315 | $cmcount = $DB->count_records('course_modules', array('id' => $cm->id)); | |
1316 | $this->assertEmpty($cmcount); | |
1317 | ||
1318 | // Verify event assignment events have been removed. | |
1319 | $eventcount = $DB->count_records('event', array('instance' => $assign->id, 'modulename' => 'assign')); | |
1320 | $this->assertEmpty($eventcount); | |
1321 | } | |
35ad79e2 MN |
1322 | |
1323 | /** | |
1324 | * Test that triggering a course_created event works as expected. | |
1325 | */ | |
1326 | public function test_course_created_event() { | |
1327 | $this->resetAfterTest(); | |
1328 | ||
1329 | // Catch the events. | |
1330 | $sink = $this->redirectEvents(); | |
1331 | ||
1332 | // Create the course. | |
1333 | $course = $this->getDataGenerator()->create_course(); | |
1334 | ||
1335 | // Capture the event. | |
1336 | $events = $sink->get_events(); | |
1337 | $sink->close(); | |
1338 | ||
1339 | // Validate the event. | |
1340 | $event = $events[0]; | |
1341 | $this->assertInstanceOf('\core\event\course_created', $event); | |
1342 | $this->assertEquals('course', $event->objecttable); | |
1343 | $this->assertEquals($course->id, $event->objectid); | |
1344 | $this->assertEquals(context_course::instance($course->id)->id, $event->contextid); | |
1345 | $this->assertEquals($course, $event->get_record_snapshot('course', $course->id)); | |
1346 | $this->assertEquals('course_created', $event->get_legacy_eventname()); | |
1347 | $this->assertEventLegacyData($course, $event); | |
1348 | $expectedlog = array(SITEID, 'course', 'new', 'view.php?id=' . $course->id, $course->fullname . ' (ID ' . $course->id . ')'); | |
1349 | $this->assertEventLegacyLogData($expectedlog, $event); | |
1350 | } | |
4fd391d5 MN |
1351 | |
1352 | /** | |
1353 | * Test that triggering a course_updated event works as expected. | |
1354 | */ | |
1355 | public function test_course_updated_event() { | |
1356 | global $DB; | |
1357 | ||
1358 | $this->resetAfterTest(); | |
1359 | ||
e5959771 | 1360 | // Create a course. |
4fd391d5 MN |
1361 | $course = $this->getDataGenerator()->create_course(); |
1362 | ||
e5959771 MN |
1363 | // Create a category we are going to move this course to. |
1364 | $category = $this->getDataGenerator()->create_category(); | |
1365 | ||
1366 | // Catch the update events. | |
4fd391d5 MN |
1367 | $sink = $this->redirectEvents(); |
1368 | ||
1369 | // Keep track of the old sortorder. | |
1370 | $sortorder = $course->sortorder; | |
1371 | ||
e5959771 | 1372 | // Call update_course which will trigger a course_updated event. |
4fd391d5 MN |
1373 | update_course($course); |
1374 | ||
1375 | // Return the updated course information from the DB. | |
e5959771 | 1376 | $updatedcourse = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); |
4fd391d5 | 1377 | |
e5959771 MN |
1378 | // Now move the course to the category, this will also trigger an event. |
1379 | move_courses(array($course->id), $category->id); | |
4fd391d5 | 1380 | |
e5959771 MN |
1381 | // Return the moved course information from the DB. |
1382 | $movedcourse = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); | |
1383 | ||
1384 | // Now we want to set the sortorder back to what it was before fix_course_sortorder() was called. The reason for | |
1385 | // this is because update_course() and move_courses() call fix_course_sortorder() which alters the sort order in | |
1386 | // the DB, but it does not set the value of the sortorder for the course object passed to the event. | |
1387 | $updatedcourse->sortorder = $sortorder; | |
1388 | $movedcourse->sortorder = $category->sortorder + MAX_COURSES_IN_CATEGORY - 1; | |
1389 | ||
1390 | // Capture the events. | |
4fd391d5 MN |
1391 | $events = $sink->get_events(); |
1392 | $sink->close(); | |
1393 | ||
e5959771 | 1394 | // Validate the events. |
4fd391d5 MN |
1395 | $event = $events[0]; |
1396 | $this->assertInstanceOf('\core\event\course_updated', $event); | |
1397 | $this->assertEquals('course', $event->objecttable); | |
e5959771 MN |
1398 | $this->assertEquals($updatedcourse->id, $event->objectid); |
1399 | $this->assertEquals(context_course::instance($updatedcourse->id)->id, $event->contextid); | |
1400 | $this->assertEquals($updatedcourse, $event->get_record_snapshot('course', $updatedcourse->id)); | |
4fd391d5 | 1401 | $this->assertEquals('course_updated', $event->get_legacy_eventname()); |
e5959771 MN |
1402 | $this->assertEventLegacyData($updatedcourse, $event); |
1403 | $expectedlog = array($updatedcourse->id, 'course', 'update', 'edit.php?id=' . $course->id, $course->id); | |
1404 | $this->assertEventLegacyLogData($expectedlog, $event); | |
1405 | ||
1406 | $event = $events[1]; | |
1407 | $this->assertInstanceOf('\core\event\course_updated', $event); | |
1408 | $this->assertEquals('course', $event->objecttable); | |
1409 | $this->assertEquals($movedcourse->id, $event->objectid); | |
1410 | $this->assertEquals(context_course::instance($movedcourse->id)->id, $event->contextid); | |
1411 | $this->assertEquals($movedcourse, $event->get_record_snapshot('course', $movedcourse->id)); | |
1412 | $this->assertEquals('course_updated', $event->get_legacy_eventname()); | |
9e2d9135 | 1413 | $this->assertEventLegacyData($movedcourse, $event); |
e5959771 | 1414 | $expectedlog = array($movedcourse->id, 'course', 'move', 'edit.php?id=' . $movedcourse->id, $movedcourse->id); |
4fd391d5 MN |
1415 | $this->assertEventLegacyLogData($expectedlog, $event); |
1416 | } | |
bc3c5b22 MN |
1417 | |
1418 | /** | |
1419 | * Test that triggering a course_deleted event works as expected. | |
1420 | */ | |
1421 | public function test_course_deleted_event() { | |
1422 | $this->resetAfterTest(); | |
1423 | ||
1424 | // Create the course. | |
1425 | $course = $this->getDataGenerator()->create_course(); | |
1426 | ||
1427 | // Save the course context before we delete the course. | |
1428 | $coursecontext = context_course::instance($course->id); | |
1429 | ||
1430 | // Catch the update event. | |
1431 | $sink = $this->redirectEvents(); | |
1432 | ||
1433 | // Call delete_course() which will trigger the course_deleted event and the course_content_deleted | |
1434 | // event. This function prints out data to the screen, which we do not want during a PHPUnit test, | |
1435 | // so use ob_start and ob_end_clean to prevent this. | |
1436 | ob_start(); | |
1437 | delete_course($course); | |
1438 | ob_end_clean(); | |
1439 | ||
1440 | // Capture the event. | |
1441 | $events = $sink->get_events(); | |
1442 | $sink->close(); | |
1443 | ||
1444 | // Validate the event. | |
ec8f23de | 1445 | $event = $events[1]; |
bc3c5b22 MN |
1446 | $this->assertInstanceOf('\core\event\course_deleted', $event); |
1447 | $this->assertEquals('course', $event->objecttable); | |
1448 | $this->assertEquals($course->id, $event->objectid); | |
1449 | $this->assertEquals($coursecontext->id, $event->contextid); | |
1450 | $this->assertEquals($course, $event->get_record_snapshot('course', $course->id)); | |
1451 | $this->assertEquals('course_deleted', $event->get_legacy_eventname()); | |
1452 | // The legacy data also passed the context in the course object. | |
1453 | $course->context = $coursecontext; | |
1454 | $this->assertEventLegacyData($course, $event); | |
1455 | $expectedlog = array(SITEID, 'course', 'delete', 'view.php?id=' . $course->id, $course->fullname . '(ID ' . $course->id . ')'); | |
1456 | $this->assertEventLegacyLogData($expectedlog, $event); | |
1457 | } | |
ec8f23de MN |
1458 | |
1459 | /** | |
1460 | * Test that triggering a course_content_deleted event works as expected. | |
1461 | */ | |
1462 | public function test_course_content_deleted_event() { | |
1463 | global $DB; | |
1464 | ||
1465 | $this->resetAfterTest(); | |
1466 | ||
1467 | // Create the course. | |
1468 | $course = $this->getDataGenerator()->create_course(); | |
1469 | ||
1470 | // Get the course from the DB. The data generator adds some extra properties, such as | |
1471 | // numsections, to the course object which will fail the assertions later on. | |
1472 | $course = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); | |
1473 | ||
1474 | // Save the course context before we delete the course. | |
1475 | $coursecontext = context_course::instance($course->id); | |
1476 | ||
1477 | // Catch the update event. | |
1478 | $sink = $this->redirectEvents(); | |
1479 | ||
1480 | // Call remove_course_contents() which will trigger the course_content_deleted event. | |
1481 | // This function prints out data to the screen, which we do not want during a PHPUnit | |
1482 | // test, so use ob_start and ob_end_clean to prevent this. | |
1483 | ob_start(); | |
1484 | remove_course_contents($course->id); | |
1485 | ob_end_clean(); | |
1486 | ||
1487 | // Capture the event. | |
1488 | $events = $sink->get_events(); | |
1489 | $sink->close(); | |
1490 | ||
1491 | // Validate the event. | |
1492 | $event = $events[0]; | |
1493 | $this->assertInstanceOf('\core\event\course_content_deleted', $event); | |
1494 | $this->assertEquals('course', $event->objecttable); | |
1495 | $this->assertEquals($course->id, $event->objectid); | |
1496 | $this->assertEquals($coursecontext->id, $event->contextid); | |
1497 | $this->assertEquals($course, $event->get_record_snapshot('course', $course->id)); | |
1498 | $this->assertEquals('course_content_removed', $event->get_legacy_eventname()); | |
1499 | // The legacy data also passed the context and options in the course object. | |
1500 | $course->context = $coursecontext; | |
1501 | $course->options = array(); | |
1502 | $this->assertEventLegacyData($course, $event); | |
1503 | } | |
7240cd92 MN |
1504 | |
1505 | /** | |
1506 | * Test that triggering a course_category_deleted event works as expected. | |
1507 | */ | |
1508 | public function test_course_category_deleted_event() { | |
1509 | $this->resetAfterTest(); | |
1510 | ||
1511 | // Create a category. | |
1512 | $category = $this->getDataGenerator()->create_category(); | |
1513 | ||
1514 | // Save the context before it is deleted. | |
1515 | $categorycontext = context_coursecat::instance($category->id); | |
1516 | ||
1517 | // Catch the update event. | |
1518 | $sink = $this->redirectEvents(); | |
1519 | ||
1520 | // Delete the category. | |
1521 | $category->delete_full(); | |
1522 | ||
1523 | // Capture the event. | |
1524 | $events = $sink->get_events(); | |
1525 | $sink->close(); | |
1526 | ||
1527 | // Validate the event. | |
1528 | $event = $events[0]; | |
1529 | $this->assertInstanceOf('\core\event\course_category_deleted', $event); | |
1530 | $this->assertEquals('course_categories', $event->objecttable); | |
1531 | $this->assertEquals($category->id, $event->objectid); | |
1532 | $this->assertEquals($categorycontext->id, $event->contextid); | |
1533 | $this->assertEquals('course_category_deleted', $event->get_legacy_eventname()); | |
1534 | $this->assertEventLegacyData($category, $event); | |
1535 | $expectedlog = array(SITEID, 'category', 'delete', 'index.php', $category->name . '(ID ' . $category->id . ')'); | |
1536 | $this->assertEventLegacyLogData($expectedlog, $event); | |
1537 | ||
1538 | // Create two categories. | |
1539 | $category = $this->getDataGenerator()->create_category(); | |
1540 | $category2 = $this->getDataGenerator()->create_category(); | |
1541 | ||
1542 | // Save the context before it is moved and then deleted. | |
1543 | $category2context = context_coursecat::instance($category2->id); | |
1544 | ||
1545 | // Catch the update event. | |
1546 | $sink = $this->redirectEvents(); | |
1547 | ||
1548 | // Move the category. | |
1549 | $category2->delete_move($category->id); | |
1550 | ||
1551 | // Capture the event. | |
1552 | $events = $sink->get_events(); | |
1553 | $sink->close(); | |
1554 | ||
1555 | // Validate the event. | |
1556 | $event = $events[0]; | |
1557 | $this->assertInstanceOf('\core\event\course_category_deleted', $event); | |
1558 | $this->assertEquals('course_categories', $event->objecttable); | |
1559 | $this->assertEquals($category2->id, $event->objectid); | |
1560 | $this->assertEquals($category2context->id, $event->contextid); | |
1561 | $this->assertEquals('course_category_deleted', $event->get_legacy_eventname()); | |
9e2d9135 | 1562 | $this->assertEventLegacyData($category2, $event); |
7240cd92 MN |
1563 | $expectedlog = array(SITEID, 'category', 'delete', 'index.php', $category2->name . '(ID ' . $category2->id . ')'); |
1564 | $this->assertEventLegacyLogData($expectedlog, $event); | |
1565 | } | |
02cbb621 MN |
1566 | |
1567 | /** | |
1568 | * Test that triggering a course_restored event works as expected. | |
1569 | */ | |
1570 | public function test_course_restored_event() { | |
1571 | global $CFG; | |
1572 | ||
1573 | // Get the necessary files to perform backup and restore. | |
1574 | require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); | |
1575 | require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php'); | |
1576 | ||
1577 | $this->resetAfterTest(); | |
1578 | ||
1579 | // Set to admin user. | |
1580 | $this->setAdminUser(); | |
1581 | ||
1582 | // The user id is going to be 2 since we are the admin user. | |
1583 | $userid = 2; | |
1584 | ||
1585 | // Create a course. | |
1586 | $course = $this->getDataGenerator()->create_course(); | |
1587 | ||
1588 | // Create backup file and save it to the backup location. | |
1589 | $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, | |
1590 | backup::INTERACTIVE_NO, backup::MODE_GENERAL, $userid); | |
1591 | $bc->execute_plan(); | |
1592 | $results = $bc->get_results(); | |
1593 | $file = $results['backup_destination']; | |
1594 | $fp = get_file_packer(); | |
1595 | $filepath = $CFG->dataroot . '/temp/backup/test-restore-course-event'; | |
1596 | $file->extract_to_pathname($fp, $filepath); | |
1597 | $bc->destroy(); | |
1598 | unset($bc); | |
1599 | ||
1600 | // Now we want to catch the restore course event. | |
1601 | $sink = $this->redirectEvents(); | |
1602 | ||
1603 | // Now restore the course to trigger the event. | |
1604 | $rc = new restore_controller('test-restore-course-event', $course->id, backup::INTERACTIVE_NO, | |
1605 | backup::MODE_GENERAL, $userid, backup::TARGET_NEW_COURSE); | |
1606 | $rc->execute_precheck(); | |
1607 | $rc->execute_plan(); | |
1608 | ||
1609 | // Capture the event. | |
1610 | $events = $sink->get_events(); | |
1611 | $sink->close(); | |
1612 | ||
1613 | // Validate the event. | |
1614 | $event = $events[0]; | |
1615 | $this->assertInstanceOf('\core\event\course_restored', $event); | |
1616 | $this->assertEquals('course', $event->objecttable); | |
1617 | $this->assertEquals($rc->get_courseid(), $event->objectid); | |
1618 | $this->assertEquals(context_course::instance($rc->get_courseid())->id, $event->contextid); | |
1619 | $this->assertEquals('course_restored', $event->get_legacy_eventname()); | |
1620 | $legacydata = (object) array( | |
1621 | 'courseid' => $rc->get_courseid(), | |
1622 | 'userid' => $rc->get_userid(), | |
1623 | 'type' => $rc->get_type(), | |
1624 | 'target' => $rc->get_target(), | |
1625 | 'mode' => $rc->get_mode(), | |
1626 | 'operation' => $rc->get_operation(), | |
1627 | 'samesite' => $rc->is_samesite() | |
1628 | ); | |
1629 | $this->assertEventLegacyData($legacydata, $event); | |
1630 | ||
1631 | // Destroy the resource controller since we are done using it. | |
1632 | $rc->destroy(); | |
1633 | unset($rc); | |
1634 | ||
1635 | // Clear the time limit, otherwise PHPUnit complains. | |
1636 | set_time_limit(0); | |
1637 | } | |
5a10d2a7 | 1638 | |
ed29bf0f RT |
1639 | /** |
1640 | * Test that triggering a course_section_updated event works as expected. | |
1641 | */ | |
1642 | public function test_course_section_updated_event() { | |
1643 | global $DB; | |
1644 | ||
1645 | $this->resetAfterTest(); | |
1646 | ||
1647 | // Create the course with sections. | |
1648 | $course = $this->getDataGenerator()->create_course(array('numsections' => 10), array('createsections' => true)); | |
1649 | $sections = $DB->get_records('course_sections', array('course' => $course->id)); | |
1650 | ||
1651 | $coursecontext = context_course::instance($course->id); | |
1652 | ||
1653 | $section = array_pop($sections); | |
1654 | $section->name = 'Test section'; | |
1655 | $section->summary = 'Test section summary'; | |
1656 | $DB->update_record('course_sections', $section); | |
1657 | ||
1658 | // Trigger an event for course section update. | |
1659 | $event = \core\event\course_section_updated::create( | |
1660 | array( | |
1661 | 'objectid' => $section->id, | |
1662 | 'courseid' => $course->id, | |
1663 | 'context' => context_course::instance($course->id) | |
1664 | ) | |
1665 | ); | |
1666 | $event->add_record_snapshot('course_sections', $section); | |
1667 | // Trigger and catch event. | |
1668 | $sink = $this->redirectEvents(); | |
1669 | $event->trigger(); | |
1670 | $events = $sink->get_events(); | |
1671 | $sink->close(); | |
1672 | ||
1673 | // Validate the event. | |
1674 | $event = $events[0]; | |
1675 | $this->assertInstanceOf('\core\event\course_section_updated', $event); | |
1676 | $this->assertEquals('course_sections', $event->objecttable); | |
1677 | $this->assertEquals($section->id, $event->objectid); | |
1678 | $this->assertEquals($course->id, $event->courseid); | |
1679 | $this->assertEquals($coursecontext->id, $event->contextid); | |
1680 | $expecteddesc = 'Course ' . $event->courseid . ' section ' . $event->other['sectionnum'] . ' updated by user ' . $event->userid; | |
1681 | $this->assertEquals($expecteddesc, $event->get_description()); | |
1682 | $this->assertEquals($section, $event->get_record_snapshot('course_sections', $event->objectid)); | |
1683 | $id = $section->id; | |
1684 | $sectionnum = $section->section; | |
1685 | $expectedlegacydata = array($course->id, "course", "editsection", 'editsection.php?id=' . $id, $sectionnum); | |
1686 | $this->assertEventLegacyLogData($expectedlegacydata, $event); | |
1687 | } | |
354b214c | 1688 | } |