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); | |
9930e426 CF |
605 | |
606 | // Ensure that the shortname isn't duplicated. | |
607 | try { | |
608 | $created = create_course($course); | |
2793260f | 609 | $this->fail('Exception expected'); |
9930e426 | 610 | } catch (moodle_exception $e) { |
2793260f | 611 | $this->assertSame(get_string('shortnametaken', 'error', $course->shortname), $e->getMessage()); |
9930e426 | 612 | } |
9930e426 CF |
613 | |
614 | // Ensure that the idnumber isn't duplicated. | |
615 | $course->shortname .= '1'; | |
616 | try { | |
617 | $created = create_course($course); | |
2793260f | 618 | $this->fail('Exception expected'); |
9930e426 | 619 | } catch (moodle_exception $e) { |
2793260f | 620 | $this->assertSame(get_string('courseidnumbertaken', 'error', $course->idnumber), $e->getMessage()); |
9930e426 | 621 | } |
f70bfb84 FM |
622 | } |
623 | ||
384c3510 MG |
624 | public function test_create_course_with_generator() { |
625 | global $DB; | |
626 | $this->resetAfterTest(true); | |
627 | $course = $this->getDataGenerator()->create_course(); | |
628 | ||
629 | // Ensure default section is created. | |
630 | $sectioncreated = $DB->record_exists('course_sections', array('course' => $course->id, 'section' => 0)); | |
631 | $this->assertTrue($sectioncreated); | |
632 | } | |
633 | ||
634 | public function test_create_course_sections() { | |
635 | global $DB; | |
636 | $this->resetAfterTest(true); | |
637 | ||
638 | $course = $this->getDataGenerator()->create_course( | |
639 | array('shortname' => 'GrowingCourse', | |
640 | 'fullname' => 'Growing Course', | |
641 | 'numsections' => 5), | |
642 | array('createsections' => true)); | |
643 | ||
4a3fb71c | 644 | // Ensure all 6 (0-5) sections were created and course content cache works properly |
384c3510 MG |
645 | $sectionscreated = array_keys(get_fast_modinfo($course)->get_section_info_all()); |
646 | $this->assertEquals(range(0, $course->numsections), $sectionscreated); | |
647 | ||
648 | // this will do nothing, section already exists | |
649 | $this->assertFalse(course_create_sections_if_missing($course, $course->numsections)); | |
650 | ||
651 | // this will create new section | |
652 | $this->assertTrue(course_create_sections_if_missing($course, $course->numsections + 1)); | |
653 | ||
654 | // Ensure all 7 (0-6) sections were created and modinfo/sectioninfo cache works properly | |
655 | $sectionscreated = array_keys(get_fast_modinfo($course)->get_section_info_all()); | |
656 | $this->assertEquals(range(0, $course->numsections + 1), $sectionscreated); | |
657 | } | |
658 | ||
5536a561 FD |
659 | public function test_update_course() { |
660 | global $DB; | |
661 | ||
662 | $this->resetAfterTest(); | |
c3bf6181 MN |
663 | |
664 | $defaultcategory = $DB->get_field_select('course_categories', 'MIN(id)', 'parent = 0'); | |
5536a561 FD |
665 | |
666 | $course = new stdClass(); | |
667 | $course->fullname = 'Apu loves Unit TÉsts'; | |
668 | $course->shortname = 'test1'; | |
669 | $course->idnumber = '1'; | |
670 | $course->summary = 'Awesome!'; | |
671 | $course->summaryformat = FORMAT_PLAIN; | |
672 | $course->format = 'topics'; | |
673 | $course->newsitems = 0; | |
674 | $course->numsections = 5; | |
675 | $course->category = $defaultcategory; | |
5536a561 FD |
676 | |
677 | $created = create_course($course); | |
678 | // Ensure the checks only work on idnumber/shortname that are not already ours. | |
c3bf6181 | 679 | update_course($created); |
5536a561 FD |
680 | |
681 | $course->shortname = 'test2'; | |
682 | $course->idnumber = '2'; | |
683 | ||
684 | $created2 = create_course($course); | |
685 | ||
686 | // Test duplicate idnumber. | |
687 | $created2->idnumber = '1'; | |
688 | try { | |
689 | update_course($created2); | |
690 | $this->fail('Expected exception when trying to update a course with duplicate idnumber'); | |
691 | } catch (moodle_exception $e) { | |
692 | $this->assertEquals(get_string('courseidnumbertaken', 'error', $created2->idnumber), $e->getMessage()); | |
693 | } | |
694 | ||
695 | // Test duplicate shortname. | |
696 | $created2->idnumber = '2'; | |
697 | $created2->shortname = 'test1'; | |
5536a561 FD |
698 | try { |
699 | update_course($created2); | |
700 | $this->fail('Expected exception when trying to update a course with a duplicate shortname'); | |
701 | } catch (moodle_exception $e) { | |
702 | $this->assertEquals(get_string('shortnametaken', 'error', $created2->shortname), $e->getMessage()); | |
703 | } | |
704 | } | |
705 | ||
5523c344 | 706 | public function test_course_add_cm_to_section() { |
707 | global $DB; | |
708 | $this->resetAfterTest(true); | |
709 | ||
710 | // Create course with 1 section. | |
711 | $course = $this->getDataGenerator()->create_course( | |
712 | array('shortname' => 'GrowingCourse', | |
713 | 'fullname' => 'Growing Course', | |
714 | 'numsections' => 1), | |
715 | array('createsections' => true)); | |
716 | ||
717 | // Trash modinfo. | |
718 | rebuild_course_cache($course->id, true); | |
719 | ||
720 | // Create some cms for testing. | |
721 | $cmids = array(); | |
722 | for ($i=0; $i<4; $i++) { | |
723 | $cmids[$i] = $DB->insert_record('course_modules', array('course' => $course->id)); | |
724 | } | |
725 | ||
726 | // Add it to section that exists. | |
727 | course_add_cm_to_section($course, $cmids[0], 1); | |
728 | ||
729 | // Check it got added to sequence. | |
730 | $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 1)); | |
731 | $this->assertEquals($cmids[0], $sequence); | |
732 | ||
733 | // Add a second, this time using courseid variant of parameters. | |
4a3fb71c | 734 | $coursecacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id)); |
5523c344 | 735 | course_add_cm_to_section($course->id, $cmids[1], 1); |
736 | $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 1)); | |
737 | $this->assertEquals($cmids[0] . ',' . $cmids[1], $sequence); | |
738 | ||
4a3fb71c MG |
739 | // Check that modinfo cache was reset but not rebuilt (important for performance if calling repeatedly). |
740 | $this->assertGreaterThan($coursecacherev, $DB->get_field('course', 'cacherev', array('id' => $course->id))); | |
741 | $this->assertEmpty(cache::make('core', 'coursemodinfo')->get($course->id)); | |
5523c344 | 742 | |
743 | // Add one to section that doesn't exist (this might rebuild modinfo). | |
744 | course_add_cm_to_section($course, $cmids[2], 2); | |
745 | $this->assertEquals(3, $DB->count_records('course_sections', array('course' => $course->id))); | |
746 | $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 2)); | |
747 | $this->assertEquals($cmids[2], $sequence); | |
748 | ||
749 | // Add using the 'before' option. | |
750 | course_add_cm_to_section($course, $cmids[3], 2, $cmids[2]); | |
751 | $this->assertEquals(3, $DB->count_records('course_sections', array('course' => $course->id))); | |
752 | $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 2)); | |
753 | $this->assertEquals($cmids[3] . ',' . $cmids[2], $sequence); | |
754 | } | |
755 | ||
354b214c PS |
756 | public function test_reorder_sections() { |
757 | global $DB; | |
758 | $this->resetAfterTest(true); | |
759 | ||
760 | $this->getDataGenerator()->create_course(array('numsections'=>5), array('createsections'=>true)); | |
761 | $course = $this->getDataGenerator()->create_course(array('numsections'=>10), array('createsections'=>true)); | |
762 | $oldsections = array(); | |
763 | $sections = array(); | |
3a222db2 | 764 | foreach ($DB->get_records('course_sections', array('course'=>$course->id), 'id') as $section) { |
354b214c PS |
765 | $oldsections[$section->section] = $section->id; |
766 | $sections[$section->id] = $section->section; | |
767 | } | |
768 | ksort($oldsections); | |
769 | ||
770 | $neworder = reorder_sections($sections, 2, 4); | |
771 | $neworder = array_keys($neworder); | |
772 | $this->assertEquals($oldsections[0], $neworder[0]); | |
773 | $this->assertEquals($oldsections[1], $neworder[1]); | |
774 | $this->assertEquals($oldsections[2], $neworder[4]); | |
775 | $this->assertEquals($oldsections[3], $neworder[2]); | |
776 | $this->assertEquals($oldsections[4], $neworder[3]); | |
777 | $this->assertEquals($oldsections[5], $neworder[5]); | |
778 | $this->assertEquals($oldsections[6], $neworder[6]); | |
779 | ||
eb01aa2c RT |
780 | $neworder = reorder_sections($sections, 4, 2); |
781 | $neworder = array_keys($neworder); | |
782 | $this->assertEquals($oldsections[0], $neworder[0]); | |
783 | $this->assertEquals($oldsections[1], $neworder[1]); | |
784 | $this->assertEquals($oldsections[2], $neworder[3]); | |
785 | $this->assertEquals($oldsections[3], $neworder[4]); | |
786 | $this->assertEquals($oldsections[4], $neworder[2]); | |
787 | $this->assertEquals($oldsections[5], $neworder[5]); | |
788 | $this->assertEquals($oldsections[6], $neworder[6]); | |
789 | ||
354b214c PS |
790 | $neworder = reorder_sections(1, 2, 4); |
791 | $this->assertFalse($neworder); | |
792 | } | |
793 | ||
3d8fe482 | 794 | public function test_move_section_down() { |
354b214c PS |
795 | global $DB; |
796 | $this->resetAfterTest(true); | |
797 | ||
798 | $this->getDataGenerator()->create_course(array('numsections'=>5), array('createsections'=>true)); | |
799 | $course = $this->getDataGenerator()->create_course(array('numsections'=>10), array('createsections'=>true)); | |
800 | $oldsections = array(); | |
801 | foreach ($DB->get_records('course_sections', array('course'=>$course->id)) as $section) { | |
802 | $oldsections[$section->section] = $section->id; | |
803 | } | |
804 | ksort($oldsections); | |
805 | ||
3d8fe482 | 806 | // Test move section down.. |
354b214c PS |
807 | move_section_to($course, 2, 4); |
808 | $sections = array(); | |
809 | foreach ($DB->get_records('course_sections', array('course'=>$course->id)) as $section) { | |
810 | $sections[$section->section] = $section->id; | |
811 | } | |
812 | ksort($sections); | |
813 | ||
814 | $this->assertEquals($oldsections[0], $sections[0]); | |
815 | $this->assertEquals($oldsections[1], $sections[1]); | |
816 | $this->assertEquals($oldsections[2], $sections[4]); | |
817 | $this->assertEquals($oldsections[3], $sections[2]); | |
818 | $this->assertEquals($oldsections[4], $sections[3]); | |
819 | $this->assertEquals($oldsections[5], $sections[5]); | |
820 | $this->assertEquals($oldsections[6], $sections[6]); | |
821 | } | |
822 | ||
3d8fe482 DP |
823 | public function test_move_section_up() { |
824 | global $DB; | |
825 | $this->resetAfterTest(true); | |
826 | ||
827 | $this->getDataGenerator()->create_course(array('numsections'=>5), array('createsections'=>true)); | |
828 | $course = $this->getDataGenerator()->create_course(array('numsections'=>10), array('createsections'=>true)); | |
829 | $oldsections = array(); | |
830 | foreach ($DB->get_records('course_sections', array('course'=>$course->id)) as $section) { | |
831 | $oldsections[$section->section] = $section->id; | |
832 | } | |
833 | ksort($oldsections); | |
834 | ||
835 | // Test move section up.. | |
836 | move_section_to($course, 6, 4); | |
837 | $sections = array(); | |
838 | foreach ($DB->get_records('course_sections', array('course'=>$course->id)) as $section) { | |
839 | $sections[$section->section] = $section->id; | |
840 | } | |
841 | ksort($sections); | |
842 | ||
843 | $this->assertEquals($oldsections[0], $sections[0]); | |
844 | $this->assertEquals($oldsections[1], $sections[1]); | |
845 | $this->assertEquals($oldsections[2], $sections[2]); | |
846 | $this->assertEquals($oldsections[3], $sections[3]); | |
847 | $this->assertEquals($oldsections[4], $sections[5]); | |
848 | $this->assertEquals($oldsections[5], $sections[6]); | |
849 | $this->assertEquals($oldsections[6], $sections[4]); | |
850 | } | |
851 | ||
852 | public function test_move_section_marker() { | |
853 | global $DB; | |
854 | $this->resetAfterTest(true); | |
855 | ||
856 | $this->getDataGenerator()->create_course(array('numsections'=>5), array('createsections'=>true)); | |
857 | $course = $this->getDataGenerator()->create_course(array('numsections'=>10), array('createsections'=>true)); | |
858 | ||
859 | // Set course marker to the section we are going to move.. | |
860 | course_set_marker($course->id, 2); | |
861 | // Verify that the course marker is set correctly. | |
862 | $course = $DB->get_record('course', array('id' => $course->id)); | |
863 | $this->assertEquals(2, $course->marker); | |
864 | ||
865 | // Test move the marked section down.. | |
866 | move_section_to($course, 2, 4); | |
867 | ||
868 | // Verify that the coruse marker has been moved along with the section.. | |
869 | $course = $DB->get_record('course', array('id' => $course->id)); | |
870 | $this->assertEquals(4, $course->marker); | |
871 | ||
872 | // Test move the marked section up.. | |
873 | move_section_to($course, 4, 3); | |
874 | ||
875 | // Verify that the course marker has been moved along with the section.. | |
876 | $course = $DB->get_record('course', array('id' => $course->id)); | |
877 | $this->assertEquals(3, $course->marker); | |
878 | ||
879 | // Test moving a non-marked section above the marked section.. | |
880 | move_section_to($course, 4, 2); | |
881 | ||
882 | // Verify that the course marker has been moved down to accomodate.. | |
883 | $course = $DB->get_record('course', array('id' => $course->id)); | |
884 | $this->assertEquals(4, $course->marker); | |
885 | ||
886 | // Test moving a non-marked section below the marked section.. | |
887 | move_section_to($course, 3, 6); | |
888 | ||
889 | // Verify that the course marker has been up to accomodate.. | |
890 | $course = $DB->get_record('course', array('id' => $course->id)); | |
891 | $this->assertEquals(3, $course->marker); | |
892 | } | |
893 | ||
354b214c PS |
894 | public function test_get_course_display_name_for_list() { |
895 | global $CFG; | |
896 | $this->resetAfterTest(true); | |
897 | ||
898 | $course = $this->getDataGenerator()->create_course(array('shortname' => 'FROG101', 'fullname' => 'Introduction to pond life')); | |
899 | ||
900 | $CFG->courselistshortnames = 0; | |
901 | $this->assertEquals('Introduction to pond life', get_course_display_name_for_list($course)); | |
902 | ||
903 | $CFG->courselistshortnames = 1; | |
904 | $this->assertEquals('FROG101 Introduction to pond life', get_course_display_name_for_list($course)); | |
905 | } | |
b1a8aa73 | 906 | |
384c3510 | 907 | public function test_move_module_in_course() { |
3f61e4cb ARN |
908 | global $DB; |
909 | ||
384c3510 MG |
910 | $this->resetAfterTest(true); |
911 | // Setup fixture | |
3f61e4cb | 912 | $course = $this->getDataGenerator()->create_course(array('numsections'=>5), array('createsections' => true)); |
384c3510 MG |
913 | $forum = $this->getDataGenerator()->create_module('forum', array('course'=>$course->id)); |
914 | ||
384c3510 MG |
915 | $cms = get_fast_modinfo($course)->get_cms(); |
916 | $cm = reset($cms); | |
917 | ||
3f61e4cb ARN |
918 | $newsection = get_fast_modinfo($course)->get_section_info(3); |
919 | $oldsectionid = $cm->section; | |
920 | ||
921 | // Perform the move | |
922 | moveto_module($cm, $newsection); | |
384c3510 | 923 | |
3f61e4cb ARN |
924 | $cms = get_fast_modinfo($course)->get_cms(); |
925 | $cm = reset($cms); | |
384c3510 | 926 | |
3f61e4cb | 927 | // Check that the cached modinfo contains the correct section info |
384c3510 MG |
928 | $modinfo = get_fast_modinfo($course); |
929 | $this->assertTrue(empty($modinfo->sections[0])); | |
930 | $this->assertFalse(empty($modinfo->sections[3])); | |
3f61e4cb ARN |
931 | |
932 | // Check that the old section's sequence no longer contains this ID | |
933 | $oldsection = $DB->get_record('course_sections', array('id' => $oldsectionid)); | |
934 | $oldsequences = explode(',', $newsection->sequence); | |
935 | $this->assertFalse(in_array($cm->id, $oldsequences)); | |
936 | ||
937 | // Check that the new section's sequence now contains this ID | |
938 | $newsection = $DB->get_record('course_sections', array('id' => $newsection->id)); | |
939 | $newsequences = explode(',', $newsection->sequence); | |
940 | $this->assertTrue(in_array($cm->id, $newsequences)); | |
941 | ||
942 | // Check that the section number has been changed in the cm | |
943 | $this->assertEquals($newsection->id, $cm->section); | |
944 | ||
945 | ||
946 | // Perform a second move as some issues were only seen on the second move | |
947 | $newsection = get_fast_modinfo($course)->get_section_info(2); | |
948 | $oldsectionid = $cm->section; | |
d55f05ef | 949 | moveto_module($cm, $newsection); |
3f61e4cb | 950 | |
3f61e4cb ARN |
951 | $cms = get_fast_modinfo($course)->get_cms(); |
952 | $cm = reset($cms); | |
953 | ||
954 | // Check that the cached modinfo contains the correct section info | |
955 | $modinfo = get_fast_modinfo($course); | |
956 | $this->assertTrue(empty($modinfo->sections[0])); | |
957 | $this->assertFalse(empty($modinfo->sections[2])); | |
958 | ||
959 | // Check that the old section's sequence no longer contains this ID | |
960 | $oldsection = $DB->get_record('course_sections', array('id' => $oldsectionid)); | |
961 | $oldsequences = explode(',', $newsection->sequence); | |
962 | $this->assertFalse(in_array($cm->id, $oldsequences)); | |
963 | ||
964 | // Check that the new section's sequence now contains this ID | |
965 | $newsection = $DB->get_record('course_sections', array('id' => $newsection->id)); | |
966 | $newsequences = explode(',', $newsection->sequence); | |
967 | $this->assertTrue(in_array($cm->id, $newsequences)); | |
384c3510 | 968 | } |
f7d6e650 FM |
969 | |
970 | public function test_module_visibility() { | |
971 | $this->setAdminUser(); | |
972 | $this->resetAfterTest(true); | |
973 | ||
974 | // Create course and modules. | |
975 | $course = $this->getDataGenerator()->create_course(array('numsections' => 5)); | |
976 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); | |
977 | $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), 'course' => $course->id)); | |
978 | $modules = compact('forum', 'assign'); | |
979 | ||
980 | // Hiding the modules. | |
981 | foreach ($modules as $mod) { | |
982 | set_coursemodule_visible($mod->cmid, 0); | |
983 | $this->check_module_visibility($mod, 0, 0); | |
984 | } | |
985 | ||
986 | // Showing the modules. | |
987 | foreach ($modules as $mod) { | |
988 | set_coursemodule_visible($mod->cmid, 1); | |
989 | $this->check_module_visibility($mod, 1, 1); | |
990 | } | |
991 | } | |
992 | ||
993 | public function test_section_visibility() { | |
994 | $this->setAdminUser(); | |
995 | $this->resetAfterTest(true); | |
996 | ||
997 | // Create course. | |
998 | $course = $this->getDataGenerator()->create_course(array('numsections' => 3), array('createsections' => true)); | |
999 | ||
1000 | // Testing an empty section. | |
1001 | $sectionnumber = 1; | |
1002 | set_section_visible($course->id, $sectionnumber, 0); | |
1003 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
1004 | $this->assertEquals($section_info->visible, 0); | |
1005 | set_section_visible($course->id, $sectionnumber, 1); | |
1006 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
1007 | $this->assertEquals($section_info->visible, 1); | |
1008 | ||
1009 | // Testing a section with visible modules. | |
1010 | $sectionnumber = 2; | |
1011 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id), | |
1012 | array('section' => $sectionnumber)); | |
1013 | $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), | |
1014 | 'course' => $course->id), array('section' => $sectionnumber)); | |
1015 | $modules = compact('forum', 'assign'); | |
1016 | set_section_visible($course->id, $sectionnumber, 0); | |
1017 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
1018 | $this->assertEquals($section_info->visible, 0); | |
1019 | foreach ($modules as $mod) { | |
1020 | $this->check_module_visibility($mod, 0, 1); | |
1021 | } | |
1022 | set_section_visible($course->id, $sectionnumber, 1); | |
1023 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
1024 | $this->assertEquals($section_info->visible, 1); | |
1025 | foreach ($modules as $mod) { | |
1026 | $this->check_module_visibility($mod, 1, 1); | |
1027 | } | |
1028 | ||
1029 | // Testing a section with hidden modules, which should stay hidden. | |
1030 | $sectionnumber = 3; | |
1031 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id), | |
1032 | array('section' => $sectionnumber)); | |
1033 | $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), | |
1034 | 'course' => $course->id), array('section' => $sectionnumber)); | |
1035 | $modules = compact('forum', 'assign'); | |
1036 | foreach ($modules as $mod) { | |
1037 | set_coursemodule_visible($mod->cmid, 0); | |
1038 | $this->check_module_visibility($mod, 0, 0); | |
1039 | } | |
1040 | set_section_visible($course->id, $sectionnumber, 0); | |
1041 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
1042 | $this->assertEquals($section_info->visible, 0); | |
1043 | foreach ($modules as $mod) { | |
1044 | $this->check_module_visibility($mod, 0, 0); | |
1045 | } | |
1046 | set_section_visible($course->id, $sectionnumber, 1); | |
1047 | $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber); | |
1048 | $this->assertEquals($section_info->visible, 1); | |
1049 | foreach ($modules as $mod) { | |
1050 | $this->check_module_visibility($mod, 0, 0); | |
1051 | } | |
1052 | } | |
1053 | ||
1054 | /** | |
1055 | * Helper function to assert that a module has correctly been made visible, or hidden. | |
1056 | * | |
1057 | * @param stdClass $mod module information | |
1058 | * @param int $visibility the current state of the module | |
1059 | * @param int $visibleold the current state of the visibleold property | |
1060 | * @return void | |
1061 | */ | |
1062 | public function check_module_visibility($mod, $visibility, $visibleold) { | |
1063 | global $DB; | |
1064 | $cm = get_fast_modinfo($mod->course)->get_cm($mod->cmid); | |
1065 | $this->assertEquals($visibility, $cm->visible); | |
1066 | $this->assertEquals($visibleold, $cm->visibleold); | |
1067 | ||
1068 | // Check the module grade items. | |
1069 | $grade_items = grade_item::fetch_all(array('itemtype' => 'mod', 'itemmodule' => $cm->modname, | |
1070 | 'iteminstance' => $cm->instance, 'courseid' => $cm->course)); | |
1071 | if ($grade_items) { | |
1072 | foreach ($grade_items as $grade_item) { | |
1073 | if ($visibility) { | |
1074 | $this->assertFalse($grade_item->is_hidden(), "$cm->modname grade_item not visible"); | |
1075 | } else { | |
1076 | $this->assertTrue($grade_item->is_hidden(), "$cm->modname grade_item not hidden"); | |
1077 | } | |
1078 | } | |
1079 | } | |
1080 | ||
1081 | // Check the events visibility. | |
1082 | if ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $cm->modname))) { | |
1083 | foreach ($events as $event) { | |
1084 | $calevent = new calendar_event($event); | |
1085 | $this->assertEquals($visibility, $calevent->visible, "$cm->modname calendar_event visibility"); | |
1086 | } | |
1087 | } | |
1088 | } | |
1089 | ||
b7d3bb0f AG |
1090 | public function test_course_page_type_list() { |
1091 | global $DB; | |
1092 | $this->resetAfterTest(true); | |
1093 | ||
1094 | // Create a category. | |
1095 | $category = new stdClass(); | |
1096 | $category->name = 'Test Category'; | |
1097 | ||
1098 | $testcategory = $this->getDataGenerator()->create_category($category); | |
1099 | ||
1100 | // Create a course. | |
1101 | $course = new stdClass(); | |
1102 | $course->fullname = 'Apu loves Unit TÉsts'; | |
1103 | $course->shortname = 'Spread the lÅve'; | |
1104 | $course->idnumber = '123'; | |
1105 | $course->summary = 'Awesome!'; | |
1106 | $course->summaryformat = FORMAT_PLAIN; | |
1107 | $course->format = 'topics'; | |
1108 | $course->newsitems = 0; | |
1109 | $course->numsections = 5; | |
1110 | $course->category = $testcategory->id; | |
1111 | ||
1112 | $testcourse = $this->getDataGenerator()->create_course($course); | |
1113 | ||
1114 | // Create contexts. | |
1115 | $coursecontext = context_course::instance($testcourse->id); | |
1116 | $parentcontext = $coursecontext->get_parent_context(); // Not actually used. | |
1117 | $pagetype = 'page-course-x'; // Not used either. | |
1118 | $pagetypelist = course_page_type_list($pagetype, $parentcontext, $coursecontext); | |
1119 | ||
1120 | // Page type lists for normal courses. | |
1121 | $testpagetypelist1 = array(); | |
1122 | $testpagetypelist1['*'] = 'Any page'; | |
1123 | $testpagetypelist1['course-*'] = 'Any course page'; | |
1124 | $testpagetypelist1['course-view-*'] = 'Any type of course main page'; | |
1125 | ||
1126 | $this->assertEquals($testpagetypelist1, $pagetypelist); | |
1127 | ||
1128 | // Get the context for the front page course. | |
1129 | $sitecoursecontext = context_course::instance(SITEID); | |
1130 | $pagetypelist = course_page_type_list($pagetype, $parentcontext, $sitecoursecontext); | |
1131 | ||
1132 | // Page type list for the front page course. | |
1133 | $testpagetypelist2 = array('*' => 'Any page'); | |
1134 | $this->assertEquals($testpagetypelist2, $pagetypelist); | |
1135 | ||
1136 | // Make sure that providing no current context to the function doesn't result in an error. | |
1137 | // Calls made from generate_page_type_patterns() may provide null values. | |
1138 | $pagetypelist = course_page_type_list($pagetype, null, null); | |
1139 | $this->assertEquals($pagetypelist, $testpagetypelist1); | |
1140 | } | |
bf6b3c7a AA |
1141 | |
1142 | public function test_compare_activities_by_time_desc() { | |
1143 | ||
1144 | // Let's create some test data. | |
1145 | $activitiesivities = array(); | |
1146 | $x = new stdClass(); | |
1147 | $x->timestamp = null; | |
1148 | $activities[] = $x; | |
1149 | ||
1150 | $x = new stdClass(); | |
1151 | $x->timestamp = 1; | |
1152 | $activities[] = $x; | |
1153 | ||
1154 | $x = new stdClass(); | |
1155 | $x->timestamp = 3; | |
1156 | $activities[] = $x; | |
1157 | ||
1158 | $x = new stdClass(); | |
1159 | $x->timestamp = 0; | |
1160 | $activities[] = $x; | |
1161 | ||
1162 | $x = new stdClass(); | |
1163 | $x->timestamp = 5; | |
1164 | $activities[] = $x; | |
1165 | ||
1166 | $x = new stdClass(); | |
1167 | $activities[] = $x; | |
1168 | ||
1169 | $x = new stdClass(); | |
1170 | $x->timestamp = 5; | |
1171 | $activities[] = $x; | |
1172 | ||
1173 | // Do the sorting. | |
1174 | usort($activities, 'compare_activities_by_time_desc'); | |
1175 | ||
1176 | // Let's check the result. | |
1177 | $last = 10; | |
1178 | foreach($activities as $activity) { | |
1179 | if (empty($activity->timestamp)) { | |
1180 | $activity->timestamp = 0; | |
1181 | } | |
1182 | $this->assertLessThanOrEqual($last, $activity->timestamp); | |
1183 | } | |
1184 | } | |
1185 | ||
1186 | public function test_compare_activities_by_time_asc() { | |
1187 | ||
1188 | // Let's create some test data. | |
1189 | $activities = array(); | |
1190 | $x = new stdClass(); | |
1191 | $x->timestamp = null; | |
1192 | $activities[] = $x; | |
1193 | ||
1194 | $x = new stdClass(); | |
1195 | $x->timestamp = 1; | |
1196 | $activities[] = $x; | |
1197 | ||
1198 | $x = new stdClass(); | |
1199 | $x->timestamp = 3; | |
1200 | $activities[] = $x; | |
1201 | ||
1202 | $x = new stdClass(); | |
1203 | $x->timestamp = 0; | |
1204 | $activities[] = $x; | |
1205 | ||
1206 | $x = new stdClass(); | |
1207 | $x->timestamp = 5; | |
1208 | $activities[] = $x; | |
1209 | ||
1210 | $x = new stdClass(); | |
1211 | $activities[] = $x; | |
1212 | ||
1213 | $x = new stdClass(); | |
1214 | $x->timestamp = 5; | |
1215 | $activities[] = $x; | |
1216 | ||
1217 | // Do the sorting. | |
1218 | usort($activities, 'compare_activities_by_time_asc'); | |
1219 | ||
1220 | // Let's check the result. | |
1221 | $last = 0; | |
1222 | foreach($activities as $activity) { | |
1223 | if (empty($activity->timestamp)) { | |
1224 | $activity->timestamp = 0; | |
1225 | } | |
1226 | $this->assertGreaterThanOrEqual($last, $activity->timestamp); | |
1227 | } | |
1228 | } | |
9ab0aece | 1229 | |
1fff1b8c DP |
1230 | /** |
1231 | * Tests moving a module between hidden/visible sections and | |
1232 | * verifies that the course/module visiblity seettings are | |
1233 | * retained. | |
1234 | */ | |
1235 | public function test_moveto_module_between_hidden_sections() { | |
1236 | global $DB; | |
1237 | ||
1238 | $this->resetAfterTest(true); | |
1239 | ||
1240 | $course = $this->getDataGenerator()->create_course(array('numsections' => 4), array('createsections' => true)); | |
1241 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); | |
1242 | $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id)); | |
1243 | $quiz= $this->getDataGenerator()->create_module('quiz', array('course' => $course->id)); | |
1244 | ||
1245 | // Set the page as hidden | |
1246 | set_coursemodule_visible($page->cmid, 0); | |
1247 | ||
1248 | // Set sections 3 as hidden. | |
1249 | set_section_visible($course->id, 3, 0); | |
1250 | ||
1251 | $modinfo = get_fast_modinfo($course); | |
1252 | ||
1253 | $hiddensection = $modinfo->get_section_info(3); | |
1254 | // New section is definitely not visible: | |
1255 | $this->assertEquals($hiddensection->visible, 0); | |
1256 | ||
1257 | $forumcm = $modinfo->cms[$forum->cmid]; | |
1258 | $pagecm = $modinfo->cms[$page->cmid]; | |
1259 | ||
d55f05ef MG |
1260 | // Move the forum and the page to a hidden section, make sure moveto_module returns 0 as new visibility state. |
1261 | $this->assertEquals(0, moveto_module($forumcm, $hiddensection)); | |
1262 | $this->assertEquals(0, moveto_module($pagecm, $hiddensection)); | |
1fff1b8c | 1263 | |
1fff1b8c DP |
1264 | $modinfo = get_fast_modinfo($course); |
1265 | ||
1266 | // Verify that forum and page have been moved to the hidden section and quiz has not. | |
1267 | $this->assertContains($forum->cmid, $modinfo->sections[3]); | |
1268 | $this->assertContains($page->cmid, $modinfo->sections[3]); | |
1269 | $this->assertNotContains($quiz->cmid, $modinfo->sections[3]); | |
1270 | ||
1271 | // Verify that forum has been made invisible. | |
1272 | $forumcm = $modinfo->cms[$forum->cmid]; | |
1273 | $this->assertEquals($forumcm->visible, 0); | |
1274 | // Verify that old state has been retained. | |
1275 | $this->assertEquals($forumcm->visibleold, 1); | |
1276 | ||
1277 | // Verify that page has stayed invisible. | |
1278 | $pagecm = $modinfo->cms[$page->cmid]; | |
1279 | $this->assertEquals($pagecm->visible, 0); | |
1280 | // Verify that old state has been retained. | |
1281 | $this->assertEquals($pagecm->visibleold, 0); | |
1282 | ||
1283 | // Verify that quiz has been unaffected. | |
1284 | $quizcm = $modinfo->cms[$quiz->cmid]; | |
1285 | $this->assertEquals($quizcm->visible, 1); | |
1286 | ||
1287 | // Move forum and page back to visible section. | |
d55f05ef | 1288 | // Make sure the visibility is restored to the original value (visible for forum and hidden for page). |
1fff1b8c | 1289 | $visiblesection = $modinfo->get_section_info(2); |
d55f05ef MG |
1290 | $this->assertEquals(1, moveto_module($forumcm, $visiblesection)); |
1291 | $this->assertEquals(0, moveto_module($pagecm, $visiblesection)); | |
1fff1b8c | 1292 | |
1fff1b8c DP |
1293 | $modinfo = get_fast_modinfo($course); |
1294 | ||
d55f05ef | 1295 | // Double check that forum has been made visible. |
1fff1b8c DP |
1296 | $forumcm = $modinfo->cms[$forum->cmid]; |
1297 | $this->assertEquals($forumcm->visible, 1); | |
1298 | ||
d55f05ef | 1299 | // Double check that page has stayed invisible. |
1fff1b8c DP |
1300 | $pagecm = $modinfo->cms[$page->cmid]; |
1301 | $this->assertEquals($pagecm->visible, 0); | |
1302 | ||
d55f05ef MG |
1303 | // Move the page in the same section (this is what mod duplicate does). |
1304 | // Visibility of page remains 0. | |
1305 | $this->assertEquals(0, moveto_module($pagecm, $visiblesection, $forumcm)); | |
1fff1b8c | 1306 | |
d55f05ef | 1307 | // Double check that the the page is still hidden. |
1fff1b8c DP |
1308 | $modinfo = get_fast_modinfo($course); |
1309 | $pagecm = $modinfo->cms[$page->cmid]; | |
1310 | $this->assertEquals($pagecm->visible, 0); | |
1311 | } | |
1312 | ||
1313 | /** | |
1314 | * Tests moving a module around in the same section. moveto_module() | |
1315 | * is called this way in modduplicate. | |
1316 | */ | |
1317 | public function test_moveto_module_in_same_section() { | |
1318 | global $DB; | |
1319 | ||
1320 | $this->resetAfterTest(true); | |
1321 | ||
1322 | $course = $this->getDataGenerator()->create_course(array('numsections' => 3), array('createsections' => true)); | |
1323 | $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id)); | |
1324 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); | |
1325 | ||
1326 | // Simulate inconsistent visible/visibleold values (MDL-38713). | |
1327 | $cm = $DB->get_record('course_modules', array('id' => $page->cmid), '*', MUST_EXIST); | |
1328 | $cm->visible = 0; | |
1329 | $cm->visibleold = 1; | |
1330 | $DB->update_record('course_modules', $cm); | |
1331 | ||
1332 | $modinfo = get_fast_modinfo($course); | |
1333 | $forumcm = $modinfo->cms[$forum->cmid]; | |
1334 | $pagecm = $modinfo->cms[$page->cmid]; | |
1335 | ||
1336 | // Verify that page is hidden. | |
1337 | $this->assertEquals($pagecm->visible, 0); | |
1338 | ||
1339 | // Verify section 0 is where all mods added. | |
1340 | $section = $modinfo->get_section_info(0); | |
1341 | $this->assertEquals($section->id, $forumcm->section); | |
1342 | $this->assertEquals($section->id, $pagecm->section); | |
1343 | ||
1344 | ||
d55f05ef MG |
1345 | // Move the page inside the hidden section. Make sure it is hidden. |
1346 | $this->assertEquals(0, moveto_module($pagecm, $section, $forumcm)); | |
1fff1b8c | 1347 | |
d55f05ef | 1348 | // Double check that the the page is still hidden. |
1fff1b8c DP |
1349 | $modinfo = get_fast_modinfo($course); |
1350 | $pagecm = $modinfo->cms[$page->cmid]; | |
1351 | $this->assertEquals($pagecm->visible, 0); | |
1352 | } | |
e52c1ea6 DP |
1353 | |
1354 | public function test_course_delete_module() { | |
1355 | global $DB; | |
1356 | $this->resetAfterTest(true); | |
1357 | $this->setAdminUser(); | |
1358 | ||
1359 | // Create course and modules. | |
1360 | $course = $this->getDataGenerator()->create_course(array('numsections' => 5)); | |
1361 | ||
1362 | // Generate an assignment with due date (will generate a course event). | |
1363 | $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), 'course' => $course->id)); | |
1364 | ||
1365 | $cm = get_coursemodule_from_instance('assign', $assign->id); | |
1366 | ||
1367 | // Verify context exists. | |
1368 | $this->assertInstanceOf('context_module', context_module::instance($cm->id, IGNORE_MISSING)); | |
1369 | ||
1370 | // Verify event assignment event has been generated. | |
1371 | $eventcount = $DB->count_records('event', array('instance' => $assign->id, 'modulename' => 'assign')); | |
1372 | $this->assertEquals(1, $eventcount); | |
1373 | ||
1374 | // Run delete.. | |
1375 | course_delete_module($cm->id); | |
1376 | ||
1377 | // Verify the context has been removed. | |
1378 | $this->assertFalse(context_module::instance($cm->id, IGNORE_MISSING)); | |
1379 | ||
1380 | // Verify the course_module record has been deleted. | |
1381 | $cmcount = $DB->count_records('course_modules', array('id' => $cm->id)); | |
1382 | $this->assertEmpty($cmcount); | |
1383 | ||
1384 | // Verify event assignment events have been removed. | |
1385 | $eventcount = $DB->count_records('event', array('instance' => $assign->id, 'modulename' => 'assign')); | |
1386 | $this->assertEmpty($eventcount); | |
1387 | } | |
35ad79e2 MN |
1388 | |
1389 | /** | |
1390 | * Test that triggering a course_created event works as expected. | |
1391 | */ | |
1392 | public function test_course_created_event() { | |
1393 | $this->resetAfterTest(); | |
1394 | ||
1395 | // Catch the events. | |
1396 | $sink = $this->redirectEvents(); | |
1397 | ||
1398 | // Create the course. | |
1399 | $course = $this->getDataGenerator()->create_course(); | |
1400 | ||
1401 | // Capture the event. | |
1402 | $events = $sink->get_events(); | |
1403 | $sink->close(); | |
1404 | ||
1405 | // Validate the event. | |
1406 | $event = $events[0]; | |
1407 | $this->assertInstanceOf('\core\event\course_created', $event); | |
1408 | $this->assertEquals('course', $event->objecttable); | |
1409 | $this->assertEquals($course->id, $event->objectid); | |
1410 | $this->assertEquals(context_course::instance($course->id)->id, $event->contextid); | |
1411 | $this->assertEquals($course, $event->get_record_snapshot('course', $course->id)); | |
1412 | $this->assertEquals('course_created', $event->get_legacy_eventname()); | |
1413 | $this->assertEventLegacyData($course, $event); | |
1414 | $expectedlog = array(SITEID, 'course', 'new', 'view.php?id=' . $course->id, $course->fullname . ' (ID ' . $course->id . ')'); | |
1415 | $this->assertEventLegacyLogData($expectedlog, $event); | |
1416 | } | |
4fd391d5 MN |
1417 | |
1418 | /** | |
1419 | * Test that triggering a course_updated event works as expected. | |
1420 | */ | |
1421 | public function test_course_updated_event() { | |
1422 | global $DB; | |
1423 | ||
1424 | $this->resetAfterTest(); | |
1425 | ||
e5959771 | 1426 | // Create a course. |
4fd391d5 MN |
1427 | $course = $this->getDataGenerator()->create_course(); |
1428 | ||
e5959771 MN |
1429 | // Create a category we are going to move this course to. |
1430 | $category = $this->getDataGenerator()->create_category(); | |
1431 | ||
aec8fe2f MG |
1432 | // Create a hidden category we are going to move this course to. |
1433 | $categoryhidden = $this->getDataGenerator()->create_category(array('visible' => 0)); | |
1434 | ||
e5959771 | 1435 | // Catch the update events. |
4fd391d5 MN |
1436 | $sink = $this->redirectEvents(); |
1437 | ||
1438 | // Keep track of the old sortorder. | |
1439 | $sortorder = $course->sortorder; | |
1440 | ||
e5959771 | 1441 | // Call update_course which will trigger a course_updated event. |
4fd391d5 MN |
1442 | update_course($course); |
1443 | ||
1444 | // Return the updated course information from the DB. | |
e5959771 | 1445 | $updatedcourse = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); |
4fd391d5 | 1446 | |
e5959771 MN |
1447 | // Now move the course to the category, this will also trigger an event. |
1448 | move_courses(array($course->id), $category->id); | |
4fd391d5 | 1449 | |
e5959771 MN |
1450 | // Return the moved course information from the DB. |
1451 | $movedcourse = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); | |
1452 | ||
aec8fe2f MG |
1453 | // Now move the course to the hidden category, this will also trigger an event. |
1454 | move_courses(array($course->id), $categoryhidden->id); | |
1455 | ||
1456 | // Return the moved course information from the DB. | |
1457 | $movedcoursehidden = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); | |
1458 | ||
e5959771 MN |
1459 | // Now we want to set the sortorder back to what it was before fix_course_sortorder() was called. The reason for |
1460 | // this is because update_course() and move_courses() call fix_course_sortorder() which alters the sort order in | |
1461 | // the DB, but it does not set the value of the sortorder for the course object passed to the event. | |
1462 | $updatedcourse->sortorder = $sortorder; | |
1463 | $movedcourse->sortorder = $category->sortorder + MAX_COURSES_IN_CATEGORY - 1; | |
aec8fe2f | 1464 | $movedcoursehidden->sortorder = $categoryhidden->sortorder + MAX_COURSES_IN_CATEGORY - 1; |
e5959771 MN |
1465 | |
1466 | // Capture the events. | |
4fd391d5 MN |
1467 | $events = $sink->get_events(); |
1468 | $sink->close(); | |
1469 | ||
e5959771 | 1470 | // Validate the events. |
4fd391d5 MN |
1471 | $event = $events[0]; |
1472 | $this->assertInstanceOf('\core\event\course_updated', $event); | |
1473 | $this->assertEquals('course', $event->objecttable); | |
e5959771 MN |
1474 | $this->assertEquals($updatedcourse->id, $event->objectid); |
1475 | $this->assertEquals(context_course::instance($updatedcourse->id)->id, $event->contextid); | |
1476 | $this->assertEquals($updatedcourse, $event->get_record_snapshot('course', $updatedcourse->id)); | |
4fd391d5 | 1477 | $this->assertEquals('course_updated', $event->get_legacy_eventname()); |
e5959771 MN |
1478 | $this->assertEventLegacyData($updatedcourse, $event); |
1479 | $expectedlog = array($updatedcourse->id, 'course', 'update', 'edit.php?id=' . $course->id, $course->id); | |
1480 | $this->assertEventLegacyLogData($expectedlog, $event); | |
1481 | ||
1482 | $event = $events[1]; | |
1483 | $this->assertInstanceOf('\core\event\course_updated', $event); | |
1484 | $this->assertEquals('course', $event->objecttable); | |
1485 | $this->assertEquals($movedcourse->id, $event->objectid); | |
1486 | $this->assertEquals(context_course::instance($movedcourse->id)->id, $event->contextid); | |
1487 | $this->assertEquals($movedcourse, $event->get_record_snapshot('course', $movedcourse->id)); | |
1488 | $this->assertEquals('course_updated', $event->get_legacy_eventname()); | |
9e2d9135 | 1489 | $this->assertEventLegacyData($movedcourse, $event); |
e5959771 | 1490 | $expectedlog = array($movedcourse->id, 'course', 'move', 'edit.php?id=' . $movedcourse->id, $movedcourse->id); |
4fd391d5 | 1491 | $this->assertEventLegacyLogData($expectedlog, $event); |
aec8fe2f MG |
1492 | |
1493 | $event = $events[2]; | |
1494 | $this->assertInstanceOf('\core\event\course_updated', $event); | |
1495 | $this->assertEquals('course', $event->objecttable); | |
1496 | $this->assertEquals($movedcoursehidden->id, $event->objectid); | |
1497 | $this->assertEquals(context_course::instance($movedcoursehidden->id)->id, $event->contextid); | |
1498 | $this->assertEquals($movedcoursehidden, $event->get_record_snapshot('course', $movedcoursehidden->id)); | |
1499 | $this->assertEquals('course_updated', $event->get_legacy_eventname()); | |
1500 | $this->assertEventLegacyData($movedcoursehidden, $event); | |
1501 | $expectedlog = array($movedcoursehidden->id, 'course', 'move', 'edit.php?id=' . $movedcoursehidden->id, $movedcoursehidden->id); | |
1502 | $this->assertEventLegacyLogData($expectedlog, $event); | |
4fd391d5 | 1503 | } |
bc3c5b22 MN |
1504 | |
1505 | /** | |
1506 | * Test that triggering a course_deleted event works as expected. | |
1507 | */ | |
1508 | public function test_course_deleted_event() { | |
1509 | $this->resetAfterTest(); | |
1510 | ||
1511 | // Create the course. | |
1512 | $course = $this->getDataGenerator()->create_course(); | |
1513 | ||
1514 | // Save the course context before we delete the course. | |
1515 | $coursecontext = context_course::instance($course->id); | |
1516 | ||
1517 | // Catch the update event. | |
1518 | $sink = $this->redirectEvents(); | |
1519 | ||
1520 | // Call delete_course() which will trigger the course_deleted event and the course_content_deleted | |
1521 | // event. This function prints out data to the screen, which we do not want during a PHPUnit test, | |
1522 | // so use ob_start and ob_end_clean to prevent this. | |
1523 | ob_start(); | |
1524 | delete_course($course); | |
1525 | ob_end_clean(); | |
1526 | ||
1527 | // Capture the event. | |
1528 | $events = $sink->get_events(); | |
1529 | $sink->close(); | |
1530 | ||
1531 | // Validate the event. | |
ec8f23de | 1532 | $event = $events[1]; |
bc3c5b22 MN |
1533 | $this->assertInstanceOf('\core\event\course_deleted', $event); |
1534 | $this->assertEquals('course', $event->objecttable); | |
1535 | $this->assertEquals($course->id, $event->objectid); | |
1536 | $this->assertEquals($coursecontext->id, $event->contextid); | |
1537 | $this->assertEquals($course, $event->get_record_snapshot('course', $course->id)); | |
1538 | $this->assertEquals('course_deleted', $event->get_legacy_eventname()); | |
1539 | // The legacy data also passed the context in the course object. | |
1540 | $course->context = $coursecontext; | |
1541 | $this->assertEventLegacyData($course, $event); | |
1542 | $expectedlog = array(SITEID, 'course', 'delete', 'view.php?id=' . $course->id, $course->fullname . '(ID ' . $course->id . ')'); | |
1543 | $this->assertEventLegacyLogData($expectedlog, $event); | |
1544 | } | |
ec8f23de MN |
1545 | |
1546 | /** | |
1547 | * Test that triggering a course_content_deleted event works as expected. | |
1548 | */ | |
1549 | public function test_course_content_deleted_event() { | |
1550 | global $DB; | |
1551 | ||
1552 | $this->resetAfterTest(); | |
1553 | ||
1554 | // Create the course. | |
1555 | $course = $this->getDataGenerator()->create_course(); | |
1556 | ||
1557 | // Get the course from the DB. The data generator adds some extra properties, such as | |
1558 | // numsections, to the course object which will fail the assertions later on. | |
1559 | $course = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); | |
1560 | ||
1561 | // Save the course context before we delete the course. | |
1562 | $coursecontext = context_course::instance($course->id); | |
1563 | ||
1564 | // Catch the update event. | |
1565 | $sink = $this->redirectEvents(); | |
1566 | ||
1567 | // Call remove_course_contents() which will trigger the course_content_deleted event. | |
1568 | // This function prints out data to the screen, which we do not want during a PHPUnit | |
1569 | // test, so use ob_start and ob_end_clean to prevent this. | |
1570 | ob_start(); | |
1571 | remove_course_contents($course->id); | |
1572 | ob_end_clean(); | |
1573 | ||
1574 | // Capture the event. | |
1575 | $events = $sink->get_events(); | |
1576 | $sink->close(); | |
1577 | ||
1578 | // Validate the event. | |
1579 | $event = $events[0]; | |
1580 | $this->assertInstanceOf('\core\event\course_content_deleted', $event); | |
1581 | $this->assertEquals('course', $event->objecttable); | |
1582 | $this->assertEquals($course->id, $event->objectid); | |
1583 | $this->assertEquals($coursecontext->id, $event->contextid); | |
1584 | $this->assertEquals($course, $event->get_record_snapshot('course', $course->id)); | |
1585 | $this->assertEquals('course_content_removed', $event->get_legacy_eventname()); | |
1586 | // The legacy data also passed the context and options in the course object. | |
1587 | $course->context = $coursecontext; | |
1588 | $course->options = array(); | |
1589 | $this->assertEventLegacyData($course, $event); | |
1590 | } | |
7240cd92 MN |
1591 | |
1592 | /** | |
1593 | * Test that triggering a course_category_deleted event works as expected. | |
1594 | */ | |
1595 | public function test_course_category_deleted_event() { | |
1596 | $this->resetAfterTest(); | |
1597 | ||
1598 | // Create a category. | |
1599 | $category = $this->getDataGenerator()->create_category(); | |
1600 | ||
1601 | // Save the context before it is deleted. | |
1602 | $categorycontext = context_coursecat::instance($category->id); | |
1603 | ||
1604 | // Catch the update event. | |
1605 | $sink = $this->redirectEvents(); | |
1606 | ||
1607 | // Delete the category. | |
1608 | $category->delete_full(); | |
1609 | ||
1610 | // Capture the event. | |
1611 | $events = $sink->get_events(); | |
1612 | $sink->close(); | |
1613 | ||
1614 | // Validate the event. | |
1615 | $event = $events[0]; | |
1616 | $this->assertInstanceOf('\core\event\course_category_deleted', $event); | |
1617 | $this->assertEquals('course_categories', $event->objecttable); | |
1618 | $this->assertEquals($category->id, $event->objectid); | |
1619 | $this->assertEquals($categorycontext->id, $event->contextid); | |
1620 | $this->assertEquals('course_category_deleted', $event->get_legacy_eventname()); | |
1621 | $this->assertEventLegacyData($category, $event); | |
1622 | $expectedlog = array(SITEID, 'category', 'delete', 'index.php', $category->name . '(ID ' . $category->id . ')'); | |
1623 | $this->assertEventLegacyLogData($expectedlog, $event); | |
1624 | ||
1625 | // Create two categories. | |
1626 | $category = $this->getDataGenerator()->create_category(); | |
1627 | $category2 = $this->getDataGenerator()->create_category(); | |
1628 | ||
1629 | // Save the context before it is moved and then deleted. | |
1630 | $category2context = context_coursecat::instance($category2->id); | |
1631 | ||
1632 | // Catch the update event. | |
1633 | $sink = $this->redirectEvents(); | |
1634 | ||
1635 | // Move the category. | |
1636 | $category2->delete_move($category->id); | |
1637 | ||
1638 | // Capture the event. | |
1639 | $events = $sink->get_events(); | |
1640 | $sink->close(); | |
1641 | ||
1642 | // Validate the event. | |
1643 | $event = $events[0]; | |
1644 | $this->assertInstanceOf('\core\event\course_category_deleted', $event); | |
1645 | $this->assertEquals('course_categories', $event->objecttable); | |
1646 | $this->assertEquals($category2->id, $event->objectid); | |
1647 | $this->assertEquals($category2context->id, $event->contextid); | |
1648 | $this->assertEquals('course_category_deleted', $event->get_legacy_eventname()); | |
9e2d9135 | 1649 | $this->assertEventLegacyData($category2, $event); |
7240cd92 MN |
1650 | $expectedlog = array(SITEID, 'category', 'delete', 'index.php', $category2->name . '(ID ' . $category2->id . ')'); |
1651 | $this->assertEventLegacyLogData($expectedlog, $event); | |
1652 | } | |
02cbb621 MN |
1653 | |
1654 | /** | |
1655 | * Test that triggering a course_restored event works as expected. | |
1656 | */ | |
1657 | public function test_course_restored_event() { | |
1658 | global $CFG; | |
1659 | ||
1660 | // Get the necessary files to perform backup and restore. | |
1661 | require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); | |
1662 | require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php'); | |
1663 | ||
1664 | $this->resetAfterTest(); | |
1665 | ||
1666 | // Set to admin user. | |
1667 | $this->setAdminUser(); | |
1668 | ||
1669 | // The user id is going to be 2 since we are the admin user. | |
1670 | $userid = 2; | |
1671 | ||
1672 | // Create a course. | |
1673 | $course = $this->getDataGenerator()->create_course(); | |
1674 | ||
1675 | // Create backup file and save it to the backup location. | |
1676 | $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, | |
1677 | backup::INTERACTIVE_NO, backup::MODE_GENERAL, $userid); | |
1678 | $bc->execute_plan(); | |
1679 | $results = $bc->get_results(); | |
1680 | $file = $results['backup_destination']; | |
1681 | $fp = get_file_packer(); | |
1682 | $filepath = $CFG->dataroot . '/temp/backup/test-restore-course-event'; | |
1683 | $file->extract_to_pathname($fp, $filepath); | |
1684 | $bc->destroy(); | |
1685 | unset($bc); | |
1686 | ||
1687 | // Now we want to catch the restore course event. | |
1688 | $sink = $this->redirectEvents(); | |
1689 | ||
1690 | // Now restore the course to trigger the event. | |
1691 | $rc = new restore_controller('test-restore-course-event', $course->id, backup::INTERACTIVE_NO, | |
1692 | backup::MODE_GENERAL, $userid, backup::TARGET_NEW_COURSE); | |
1693 | $rc->execute_precheck(); | |
1694 | $rc->execute_plan(); | |
1695 | ||
1696 | // Capture the event. | |
1697 | $events = $sink->get_events(); | |
1698 | $sink->close(); | |
1699 | ||
1700 | // Validate the event. | |
1701 | $event = $events[0]; | |
1702 | $this->assertInstanceOf('\core\event\course_restored', $event); | |
1703 | $this->assertEquals('course', $event->objecttable); | |
1704 | $this->assertEquals($rc->get_courseid(), $event->objectid); | |
1705 | $this->assertEquals(context_course::instance($rc->get_courseid())->id, $event->contextid); | |
1706 | $this->assertEquals('course_restored', $event->get_legacy_eventname()); | |
1707 | $legacydata = (object) array( | |
1708 | 'courseid' => $rc->get_courseid(), | |
1709 | 'userid' => $rc->get_userid(), | |
1710 | 'type' => $rc->get_type(), | |
1711 | 'target' => $rc->get_target(), | |
1712 | 'mode' => $rc->get_mode(), | |
1713 | 'operation' => $rc->get_operation(), | |
1714 | 'samesite' => $rc->is_samesite() | |
1715 | ); | |
1716 | $this->assertEventLegacyData($legacydata, $event); | |
1717 | ||
1718 | // Destroy the resource controller since we are done using it. | |
1719 | $rc->destroy(); | |
1720 | unset($rc); | |
1721 | ||
1722 | // Clear the time limit, otherwise PHPUnit complains. | |
1723 | set_time_limit(0); | |
1724 | } | |
5a10d2a7 | 1725 | |
ed29bf0f RT |
1726 | /** |
1727 | * Test that triggering a course_section_updated event works as expected. | |
1728 | */ | |
1729 | public function test_course_section_updated_event() { | |
1730 | global $DB; | |
1731 | ||
1732 | $this->resetAfterTest(); | |
1733 | ||
1734 | // Create the course with sections. | |
1735 | $course = $this->getDataGenerator()->create_course(array('numsections' => 10), array('createsections' => true)); | |
1736 | $sections = $DB->get_records('course_sections', array('course' => $course->id)); | |
1737 | ||
1738 | $coursecontext = context_course::instance($course->id); | |
1739 | ||
1740 | $section = array_pop($sections); | |
1741 | $section->name = 'Test section'; | |
1742 | $section->summary = 'Test section summary'; | |
1743 | $DB->update_record('course_sections', $section); | |
1744 | ||
1745 | // Trigger an event for course section update. | |
1746 | $event = \core\event\course_section_updated::create( | |
1747 | array( | |
1748 | 'objectid' => $section->id, | |
1749 | 'courseid' => $course->id, | |
1750 | 'context' => context_course::instance($course->id) | |
1751 | ) | |
1752 | ); | |
1753 | $event->add_record_snapshot('course_sections', $section); | |
1754 | // Trigger and catch event. | |
1755 | $sink = $this->redirectEvents(); | |
1756 | $event->trigger(); | |
1757 | $events = $sink->get_events(); | |
1758 | $sink->close(); | |
1759 | ||
1760 | // Validate the event. | |
1761 | $event = $events[0]; | |
1762 | $this->assertInstanceOf('\core\event\course_section_updated', $event); | |
1763 | $this->assertEquals('course_sections', $event->objecttable); | |
1764 | $this->assertEquals($section->id, $event->objectid); | |
1765 | $this->assertEquals($course->id, $event->courseid); | |
1766 | $this->assertEquals($coursecontext->id, $event->contextid); | |
1767 | $expecteddesc = 'Course ' . $event->courseid . ' section ' . $event->other['sectionnum'] . ' updated by user ' . $event->userid; | |
1768 | $this->assertEquals($expecteddesc, $event->get_description()); | |
1769 | $this->assertEquals($section, $event->get_record_snapshot('course_sections', $event->objectid)); | |
1770 | $id = $section->id; | |
1771 | $sectionnum = $section->section; | |
1772 | $expectedlegacydata = array($course->id, "course", "editsection", 'editsection.php?id=' . $id, $sectionnum); | |
1773 | $this->assertEventLegacyLogData($expectedlegacydata, $event); | |
1774 | } | |
749ce98e DW |
1775 | |
1776 | public function test_course_integrity_check() { | |
1777 | global $DB; | |
1778 | ||
1779 | $this->resetAfterTest(true); | |
1780 | $course = $this->getDataGenerator()->create_course(array('numsections' => 1), | |
1781 | array('createsections'=>true)); | |
1782 | ||
1783 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id), | |
1784 | array('section' => 0)); | |
1785 | $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id), | |
1786 | array('section' => 0)); | |
1787 | $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id), | |
1788 | array('section' => 0)); | |
1789 | $correctseq = join(',', array($forum->cmid, $page->cmid, $quiz->cmid)); | |
1790 | ||
1791 | $section0 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 0)); | |
1792 | $section1 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 1)); | |
1793 | $cms = $DB->get_records('course_modules', array('course' => $course->id), 'id', 'id,section'); | |
1794 | $this->assertEquals($correctseq, $section0->sequence); | |
1795 | $this->assertEmpty($section1->sequence); | |
1796 | $this->assertEquals($section0->id, $cms[$forum->cmid]->section); | |
1797 | $this->assertEquals($section0->id, $cms[$page->cmid]->section); | |
1798 | $this->assertEquals($section0->id, $cms[$quiz->cmid]->section); | |
1799 | $this->assertEmpty(course_integrity_check($course->id)); | |
1800 | ||
1801 | // Now let's make manual change in DB and let course_integrity_check() fix it: | |
1802 | ||
1803 | // 1. Module appears twice in one section. | |
1804 | $DB->update_record('course_sections', array('id' => $section0->id, 'sequence' => $section0->sequence. ','. $page->cmid)); | |
1805 | $this->assertEquals( | |
1806 | array('Failed integrity check for course ['. $course->id. | |
1807 | ']. Sequence for course section ['. $section0->id. '] is "'. | |
1808 | $section0->sequence. ','. $page->cmid. '", must be "'. | |
1809 | $section0->sequence. '"'), | |
1810 | course_integrity_check($course->id)); | |
1811 | $section0 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 0)); | |
1812 | $section1 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 1)); | |
1813 | $cms = $DB->get_records('course_modules', array('course' => $course->id), 'id', 'id,section'); | |
1814 | $this->assertEquals($correctseq, $section0->sequence); | |
1815 | $this->assertEmpty($section1->sequence); | |
1816 | $this->assertEquals($section0->id, $cms[$forum->cmid]->section); | |
1817 | $this->assertEquals($section0->id, $cms[$page->cmid]->section); | |
1818 | $this->assertEquals($section0->id, $cms[$quiz->cmid]->section); | |
1819 | ||
1820 | // 2. Module appears in two sections (last section wins). | |
1821 | $DB->update_record('course_sections', array('id' => $section1->id, 'sequence' => ''. $page->cmid)); | |
1822 | // First message about double mentioning in sequence, second message about wrong section field for $page. | |
1823 | $this->assertEquals(array( | |
1824 | 'Failed integrity check for course ['. $course->id. ']. Course module ['. $page->cmid. | |
1825 | '] must be removed from sequence of section ['. $section0->id. | |
1826 | '] because it is also present in sequence of section ['. $section1->id. ']', | |
1827 | 'Failed integrity check for course ['. $course->id. ']. Course module ['. $page->cmid. | |
1828 | '] points to section ['. $section0->id. '] instead of ['. $section1->id. ']'), | |
1829 | course_integrity_check($course->id)); | |
1830 | $section0 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 0)); | |
1831 | $section1 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 1)); | |
1832 | $cms = $DB->get_records('course_modules', array('course' => $course->id), 'id', 'id,section'); | |
1833 | $this->assertEquals($forum->cmid. ','. $quiz->cmid, $section0->sequence); | |
1834 | $this->assertEquals(''. $page->cmid, $section1->sequence); | |
1835 | $this->assertEquals($section0->id, $cms[$forum->cmid]->section); | |
1836 | $this->assertEquals($section1->id, $cms[$page->cmid]->section); | |
1837 | $this->assertEquals($section0->id, $cms[$quiz->cmid]->section); | |
1838 | ||
1839 | // 3. Module id is not present in course_section.sequence (integrity check with $fullcheck = false). | |
1840 | $DB->update_record('course_sections', array('id' => $section1->id, 'sequence' => '')); | |
1841 | $this->assertEmpty(course_integrity_check($course->id)); // Not an error! | |
1842 | $section0 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 0)); | |
1843 | $section1 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 1)); | |
1844 | $cms = $DB->get_records('course_modules', array('course' => $course->id), 'id', 'id,section'); | |
1845 | $this->assertEquals($forum->cmid. ','. $quiz->cmid, $section0->sequence); | |
1846 | $this->assertEmpty($section1->sequence); | |
1847 | $this->assertEquals($section0->id, $cms[$forum->cmid]->section); | |
1848 | $this->assertEquals($section1->id, $cms[$page->cmid]->section); // Not changed. | |
1849 | $this->assertEquals($section0->id, $cms[$quiz->cmid]->section); | |
1850 | ||
1851 | // 4. Module id is not present in course_section.sequence (integrity check with $fullcheck = true). | |
1852 | $this->assertEquals(array('Failed integrity check for course ['. $course->id. ']. Course module ['. | |
1853 | $page->cmid. '] is missing from sequence of section ['. $section1->id. ']'), | |
1854 | course_integrity_check($course->id, null, null, true)); // Error! | |
1855 | $section0 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 0)); | |
1856 | $section1 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 1)); | |
1857 | $cms = $DB->get_records('course_modules', array('course' => $course->id), 'id', 'id,section'); | |
1858 | $this->assertEquals($forum->cmid. ','. $quiz->cmid, $section0->sequence); | |
1859 | $this->assertEquals(''. $page->cmid, $section1->sequence); // Yay, module added to section. | |
1860 | $this->assertEquals($section0->id, $cms[$forum->cmid]->section); | |
1861 | $this->assertEquals($section1->id, $cms[$page->cmid]->section); // Not changed. | |
1862 | $this->assertEquals($section0->id, $cms[$quiz->cmid]->section); | |
1863 | ||
1864 | // 5. Module id is not present in course_section.sequence and it's section is invalid (integrity check with $fullcheck = true). | |
1865 | $DB->update_record('course_modules', array('id' => $page->cmid, 'section' => 8765)); | |
1866 | $DB->update_record('course_sections', array('id' => $section1->id, 'sequence' => '')); | |
1867 | $this->assertEquals(array( | |
1868 | 'Failed integrity check for course ['. $course->id. ']. Course module ['. $page->cmid. | |
1869 | '] is missing from sequence of section ['. $section1->id. ']', | |
1870 | 'Failed integrity check for course ['. $course->id. ']. Course module ['. $page->cmid. | |
1871 | '] points to section [8765] instead of ['. $section0->id. ']'), | |
1872 | course_integrity_check($course->id, null, null, true)); | |
1873 | $section0 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 0)); | |
1874 | $section1 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 1)); | |
1875 | $cms = $DB->get_records('course_modules', array('course' => $course->id), 'id', 'id,section'); | |
1876 | $this->assertEquals($forum->cmid. ','. $quiz->cmid. ','. $page->cmid, $section0->sequence); // Module added to section. | |
1877 | $this->assertEquals($section0->id, $cms[$forum->cmid]->section); | |
1878 | $this->assertEquals($section0->id, $cms[$page->cmid]->section); // Section changed to section0. | |
1879 | $this->assertEquals($section0->id, $cms[$quiz->cmid]->section); | |
1880 | ||
1881 | // 6. Module is deleted from course_modules but not deleted in sequence (integrity check with $fullcheck = true). | |
1882 | $DB->delete_records('course_modules', array('id' => $page->cmid)); | |
1883 | $this->assertEquals(array('Failed integrity check for course ['. $course->id. ']. Course module ['. | |
1884 | $page->cmid. '] does not exist but is present in the sequence of section ['. $section0->id. ']'), | |
1885 | course_integrity_check($course->id, null, null, true)); | |
1886 | $section0 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 0)); | |
1887 | $section1 = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 1)); | |
1888 | $cms = $DB->get_records('course_modules', array('course' => $course->id), 'id', 'id,section'); | |
1889 | $this->assertEquals($forum->cmid. ','. $quiz->cmid, $section0->sequence); | |
1890 | $this->assertEmpty($section1->sequence); | |
1891 | $this->assertEquals($section0->id, $cms[$forum->cmid]->section); | |
1892 | $this->assertEquals($section0->id, $cms[$quiz->cmid]->section); | |
1893 | $this->assertEquals(2, count($cms)); | |
1894 | } | |
354b214c | 1895 | } |