Commit | Line | Data |
---|---|---|
2a7a0216 JM |
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 | * External course functions unit tests | |
19 | * | |
20 | * @package core_course | |
21 | * @category external | |
22 | * @copyright 2012 Jerome Mouneyrac | |
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
24 | */ | |
25 | ||
26 | defined('MOODLE_INTERNAL') || die(); | |
27 | ||
28 | global $CFG; | |
29 | ||
30 | require_once($CFG->dirroot . '/webservice/tests/helpers.php'); | |
31 | ||
32 | /** | |
33 | * External course functions unit tests | |
34 | * | |
35 | * @package core_course | |
36 | * @category external | |
37 | * @copyright 2012 Jerome Mouneyrac | |
38 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
39 | */ | |
8252b7c2 | 40 | class core_course_externallib_testcase extends externallib_advanced_testcase { |
2a7a0216 JM |
41 | |
42 | /** | |
43 | * Tests set up | |
44 | */ | |
45 | protected function setUp() { | |
46 | global $CFG; | |
47 | require_once($CFG->dirroot . '/course/externallib.php'); | |
48 | } | |
49 | ||
c42d1818 AG |
50 | /** |
51 | * Tidy up open files that may be left open. | |
52 | */ | |
53 | protected function tearDown() { | |
54 | gc_collect_cycles(); | |
55 | } | |
56 | ||
2a7a0216 JM |
57 | /** |
58 | * Test create_categories | |
59 | */ | |
60 | public function test_create_categories() { | |
61 | ||
62 | global $DB; | |
63 | ||
64 | $this->resetAfterTest(true); | |
65 | ||
66 | // Set the required capabilities by the external function | |
67 | $contextid = context_system::instance()->id; | |
68 | $roleid = $this->assignUserCapability('moodle/category:manage', $contextid); | |
69 | ||
70 | // Create base categories. | |
71 | $category1 = new stdClass(); | |
72 | $category1->name = 'Root Test Category 1'; | |
73 | $category2 = new stdClass(); | |
74 | $category2->name = 'Root Test Category 2'; | |
75 | $category2->idnumber = 'rootcattest2'; | |
76 | $category2->desc = 'Description for root test category 1'; | |
77 | $category2->theme = 'base'; | |
78 | $categories = array( | |
79 | array('name' => $category1->name, 'parent' => 0), | |
80 | array('name' => $category2->name, 'parent' => 0, 'idnumber' => $category2->idnumber, | |
81 | 'description' => $category2->desc, 'theme' => $category2->theme) | |
82 | ); | |
83 | ||
84 | $createdcats = core_course_external::create_categories($categories); | |
85 | ||
fb695f6e JM |
86 | // We need to execute the return values cleaning process to simulate the web service server. |
87 | $createdcats = external_api::clean_returnvalue(core_course_external::create_categories_returns(), $createdcats); | |
88 | ||
2a7a0216 JM |
89 | // Initially confirm that base data was inserted correctly. |
90 | $this->assertEquals($category1->name, $createdcats[0]['name']); | |
91 | $this->assertEquals($category2->name, $createdcats[1]['name']); | |
92 | ||
93 | // Save the ids. | |
94 | $category1->id = $createdcats[0]['id']; | |
95 | $category2->id = $createdcats[1]['id']; | |
96 | ||
97 | // Create on sub category. | |
98 | $category3 = new stdClass(); | |
99 | $category3->name = 'Sub Root Test Category 3'; | |
100 | $subcategories = array( | |
101 | array('name' => $category3->name, 'parent' => $category1->id) | |
102 | ); | |
103 | ||
104 | $createdsubcats = core_course_external::create_categories($subcategories); | |
105 | ||
fb695f6e JM |
106 | // We need to execute the return values cleaning process to simulate the web service server. |
107 | $createdsubcats = external_api::clean_returnvalue(core_course_external::create_categories_returns(), $createdsubcats); | |
108 | ||
2a7a0216 JM |
109 | // Confirm that sub categories were inserted correctly. |
110 | $this->assertEquals($category3->name, $createdsubcats[0]['name']); | |
111 | ||
112 | // Save the ids. | |
113 | $category3->id = $createdsubcats[0]['id']; | |
114 | ||
115 | // Calling the ws function should provide a new sortorder to give category1, | |
116 | // category2, category3. New course categories are ordered by id not name. | |
117 | $category1 = $DB->get_record('course_categories', array('id' => $category1->id)); | |
118 | $category2 = $DB->get_record('course_categories', array('id' => $category2->id)); | |
119 | $category3 = $DB->get_record('course_categories', array('id' => $category3->id)); | |
120 | ||
db1eed70 MG |
121 | // sortorder sequence (and sortorder) must be: |
122 | // category 1 | |
123 | // category 3 | |
124 | // category 2 | |
125 | $this->assertGreaterThan($category1->sortorder, $category3->sortorder); | |
126 | $this->assertGreaterThan($category3->sortorder, $category2->sortorder); | |
2a7a0216 JM |
127 | |
128 | // Call without required capability | |
129 | $this->unassignUserCapability('moodle/category:manage', $contextid, $roleid); | |
130 | $this->setExpectedException('required_capability_exception'); | |
131 | $createdsubcats = core_course_external::create_categories($subcategories); | |
132 | ||
133 | } | |
134 | ||
135 | /** | |
136 | * Test delete categories | |
137 | */ | |
138 | public function test_delete_categories() { | |
139 | global $DB; | |
140 | ||
141 | $this->resetAfterTest(true); | |
142 | ||
143 | // Set the required capabilities by the external function | |
144 | $contextid = context_system::instance()->id; | |
145 | $roleid = $this->assignUserCapability('moodle/category:manage', $contextid); | |
146 | ||
147 | $category1 = self::getDataGenerator()->create_category(); | |
148 | $category2 = self::getDataGenerator()->create_category( | |
149 | array('parent' => $category1->id)); | |
150 | $category3 = self::getDataGenerator()->create_category(); | |
151 | $category4 = self::getDataGenerator()->create_category( | |
152 | array('parent' => $category3->id)); | |
153 | $category5 = self::getDataGenerator()->create_category( | |
154 | array('parent' => $category4->id)); | |
155 | ||
156 | //delete category 1 and 2 + delete category 4, category 5 moved under category 3 | |
157 | core_course_external::delete_categories(array( | |
158 | array('id' => $category1->id, 'recursive' => 1), | |
159 | array('id' => $category4->id) | |
160 | )); | |
161 | ||
162 | //check $category 1 and 2 are deleted | |
163 | $notdeletedcount = $DB->count_records_select('course_categories', | |
164 | 'id IN ( ' . $category1->id . ',' . $category2->id . ',' . $category4->id . ')'); | |
165 | $this->assertEquals(0, $notdeletedcount); | |
166 | ||
167 | //check that $category5 as $category3 for parent | |
168 | $dbcategory5 = $DB->get_record('course_categories', array('id' => $category5->id)); | |
169 | $this->assertEquals($dbcategory5->path, $category3->path . '/' . $category5->id); | |
170 | ||
171 | // Call without required capability | |
172 | $this->unassignUserCapability('moodle/category:manage', $contextid, $roleid); | |
173 | $this->setExpectedException('required_capability_exception'); | |
174 | $createdsubcats = core_course_external::delete_categories( | |
175 | array(array('id' => $category3->id))); | |
176 | } | |
177 | ||
178 | /** | |
179 | * Test get categories | |
180 | */ | |
181 | public function test_get_categories() { | |
182 | global $DB; | |
183 | ||
184 | $this->resetAfterTest(true); | |
7d6c58bc JM |
185 | |
186 | $generatedcats = array(); | |
2a7a0216 JM |
187 | $category1data['idnumber'] = 'idnumbercat1'; |
188 | $category1data['name'] = 'Category 1 for PHPunit test'; | |
189 | $category1data['description'] = 'Category 1 description'; | |
190 | $category1data['descriptionformat'] = FORMAT_MOODLE; | |
191 | $category1 = self::getDataGenerator()->create_category($category1data); | |
7d6c58bc | 192 | $generatedcats[$category1->id] = $category1; |
2a7a0216 JM |
193 | $category2 = self::getDataGenerator()->create_category( |
194 | array('parent' => $category1->id)); | |
7d6c58bc | 195 | $generatedcats[$category2->id] = $category2; |
2a7a0216 JM |
196 | $category6 = self::getDataGenerator()->create_category( |
197 | array('parent' => $category1->id, 'visible' => 0)); | |
7d6c58bc | 198 | $generatedcats[$category6->id] = $category6; |
2a7a0216 | 199 | $category3 = self::getDataGenerator()->create_category(); |
7d6c58bc | 200 | $generatedcats[$category3->id] = $category3; |
2a7a0216 JM |
201 | $category4 = self::getDataGenerator()->create_category( |
202 | array('parent' => $category3->id)); | |
7d6c58bc | 203 | $generatedcats[$category4->id] = $category4; |
2a7a0216 JM |
204 | $category5 = self::getDataGenerator()->create_category( |
205 | array('parent' => $category4->id)); | |
7d6c58bc | 206 | $generatedcats[$category5->id] = $category5; |
2a7a0216 JM |
207 | |
208 | // Set the required capabilities by the external function. | |
209 | $context = context_system::instance(); | |
210 | $roleid = $this->assignUserCapability('moodle/category:manage', $context->id); | |
211 | ||
212 | // Retrieve category1 + sub-categories except not visible ones | |
213 | $categories = core_course_external::get_categories(array( | |
214 | array('key' => 'id', 'value' => $category1->id), | |
215 | array('key' => 'visible', 'value' => 1)), 1); | |
216 | ||
fb695f6e JM |
217 | // We need to execute the return values cleaning process to simulate the web service server. |
218 | $categories = external_api::clean_returnvalue(core_course_external::get_categories_returns(), $categories); | |
219 | ||
2a7a0216 JM |
220 | // Check we retrieve the good total number of categories. |
221 | $this->assertEquals(2, count($categories)); | |
222 | ||
223 | // Check the return values | |
7d6c58bc JM |
224 | foreach ($categories as $category) { |
225 | $generatedcat = $generatedcats[$category['id']]; | |
226 | $this->assertEquals($category['idnumber'], $generatedcat->idnumber); | |
227 | $this->assertEquals($category['name'], $generatedcat->name); | |
228 | $this->assertEquals($category['description'], $generatedcat->description); | |
229 | $this->assertEquals($category['descriptionformat'], FORMAT_HTML); | |
230 | } | |
2a7a0216 JM |
231 | |
232 | // Check different params. | |
233 | $categories = core_course_external::get_categories(array( | |
234 | array('key' => 'id', 'value' => $category1->id), | |
235 | array('key' => 'idnumber', 'value' => $category1->idnumber), | |
236 | array('key' => 'visible', 'value' => 1)), 0); | |
fb695f6e JM |
237 | |
238 | // We need to execute the return values cleaning process to simulate the web service server. | |
239 | $categories = external_api::clean_returnvalue(core_course_external::get_categories_returns(), $categories); | |
240 | ||
2a7a0216 JM |
241 | $this->assertEquals(1, count($categories)); |
242 | ||
243 | // Retrieve categories from parent. | |
244 | $categories = core_course_external::get_categories(array( | |
245 | array('key' => 'parent', 'value' => $category3->id)), 1); | |
246 | $this->assertEquals(2, count($categories)); | |
247 | ||
248 | // Retrieve all categories. | |
249 | $categories = core_course_external::get_categories(); | |
fb695f6e JM |
250 | |
251 | // We need to execute the return values cleaning process to simulate the web service server. | |
252 | $categories = external_api::clean_returnvalue(core_course_external::get_categories_returns(), $categories); | |
253 | ||
2a7a0216 JM |
254 | $this->assertEquals($DB->count_records('course_categories'), count($categories)); |
255 | ||
256 | // Call without required capability (it will fail cause of the search on idnumber). | |
257 | $this->unassignUserCapability('moodle/category:manage', $context->id, $roleid); | |
258 | $this->setExpectedException('moodle_exception'); | |
259 | $categories = core_course_external::get_categories(array( | |
260 | array('key' => 'id', 'value' => $category1->id), | |
261 | array('key' => 'idnumber', 'value' => $category1->idnumber), | |
262 | array('key' => 'visible', 'value' => 1)), 0); | |
263 | } | |
264 | ||
265 | /** | |
266 | * Test update_categories | |
267 | */ | |
268 | public function test_update_categories() { | |
269 | global $DB; | |
270 | ||
271 | $this->resetAfterTest(true); | |
272 | ||
273 | // Set the required capabilities by the external function | |
274 | $contextid = context_system::instance()->id; | |
275 | $roleid = $this->assignUserCapability('moodle/category:manage', $contextid); | |
276 | ||
277 | // Create base categories. | |
278 | $category1data['idnumber'] = 'idnumbercat1'; | |
279 | $category1data['name'] = 'Category 1 for PHPunit test'; | |
280 | $category1data['description'] = 'Category 1 description'; | |
281 | $category1data['descriptionformat'] = FORMAT_MOODLE; | |
282 | $category1 = self::getDataGenerator()->create_category($category1data); | |
283 | $category2 = self::getDataGenerator()->create_category( | |
284 | array('parent' => $category1->id)); | |
285 | $category3 = self::getDataGenerator()->create_category(); | |
286 | $category4 = self::getDataGenerator()->create_category( | |
287 | array('parent' => $category3->id)); | |
288 | $category5 = self::getDataGenerator()->create_category( | |
289 | array('parent' => $category4->id)); | |
290 | ||
291 | // We update all category1 attribut. | |
292 | // Then we move cat4 and cat5 parent: cat3 => cat1 | |
293 | $categories = array( | |
294 | array('id' => $category1->id, | |
295 | 'name' => $category1->name . '_updated', | |
296 | 'idnumber' => $category1->idnumber . '_updated', | |
297 | 'description' => $category1->description . '_updated', | |
298 | 'descriptionformat' => FORMAT_HTML, | |
299 | 'theme' => $category1->theme), | |
300 | array('id' => $category4->id, 'parent' => $category1->id)); | |
301 | ||
302 | core_course_external::update_categories($categories); | |
303 | ||
304 | // Check the values were updated. | |
305 | $dbcategories = $DB->get_records_select('course_categories', | |
306 | 'id IN (' . $category1->id . ',' . $category2->id . ',' . $category2->id | |
307 | . ',' . $category3->id . ',' . $category4->id . ',' . $category5->id .')'); | |
308 | $this->assertEquals($category1->name . '_updated', | |
309 | $dbcategories[$category1->id]->name); | |
310 | $this->assertEquals($category1->idnumber . '_updated', | |
311 | $dbcategories[$category1->id]->idnumber); | |
312 | $this->assertEquals($category1->description . '_updated', | |
313 | $dbcategories[$category1->id]->description); | |
314 | $this->assertEquals(FORMAT_HTML, $dbcategories[$category1->id]->descriptionformat); | |
315 | ||
316 | // Check that category4 and category5 have been properly moved. | |
317 | $this->assertEquals('/' . $category1->id . '/' . $category4->id, | |
318 | $dbcategories[$category4->id]->path); | |
319 | $this->assertEquals('/' . $category1->id . '/' . $category4->id . '/' . $category5->id, | |
320 | $dbcategories[$category5->id]->path); | |
321 | ||
322 | // Call without required capability. | |
323 | $this->unassignUserCapability('moodle/category:manage', $contextid, $roleid); | |
324 | $this->setExpectedException('required_capability_exception'); | |
325 | core_course_external::update_categories($categories); | |
326 | } | |
327 | ||
328 | /** | |
329 | * Test create_courses | |
330 | */ | |
331 | public function test_create_courses() { | |
332 | global $DB; | |
333 | ||
334 | $this->resetAfterTest(true); | |
335 | ||
821676f5 JM |
336 | // Enable course completion. |
337 | set_config('enablecompletion', 1); | |
141e7d87 DP |
338 | // Enable course themes. |
339 | set_config('allowcoursethemes', 1); | |
821676f5 | 340 | |
2a7a0216 JM |
341 | // Set the required capabilities by the external function |
342 | $contextid = context_system::instance()->id; | |
343 | $roleid = $this->assignUserCapability('moodle/course:create', $contextid); | |
344 | $this->assignUserCapability('moodle/course:visibility', $contextid, $roleid); | |
345 | ||
346 | $category = self::getDataGenerator()->create_category(); | |
347 | ||
348 | // Create base categories. | |
349 | $course1['fullname'] = 'Test course 1'; | |
350 | $course1['shortname'] = 'Testcourse1'; | |
351 | $course1['categoryid'] = $category->id; | |
352 | $course2['fullname'] = 'Test course 2'; | |
353 | $course2['shortname'] = 'Testcourse2'; | |
354 | $course2['categoryid'] = $category->id; | |
355 | $course2['idnumber'] = 'testcourse2idnumber'; | |
356 | $course2['summary'] = 'Description for course 2'; | |
357 | $course2['summaryformat'] = FORMAT_MOODLE; | |
358 | $course2['format'] = 'weeks'; | |
359 | $course2['showgrades'] = 1; | |
360 | $course2['newsitems'] = 3; | |
4491273b | 361 | $course2['startdate'] = 1420092000; // 01/01/2015 |
2a7a0216 JM |
362 | $course2['numsections'] = 4; |
363 | $course2['maxbytes'] = 100000; | |
364 | $course2['showreports'] = 1; | |
365 | $course2['visible'] = 0; | |
366 | $course2['hiddensections'] = 0; | |
367 | $course2['groupmode'] = 0; | |
368 | $course2['groupmodeforce'] = 0; | |
369 | $course2['defaultgroupingid'] = 0; | |
370 | $course2['enablecompletion'] = 1; | |
2a7a0216 JM |
371 | $course2['completionnotify'] = 1; |
372 | $course2['lang'] = 'en'; | |
373 | $course2['forcetheme'] = 'base'; | |
0e984d98 MG |
374 | $course3['fullname'] = 'Test course 3'; |
375 | $course3['shortname'] = 'Testcourse3'; | |
376 | $course3['categoryid'] = $category->id; | |
377 | $course3['format'] = 'topics'; | |
378 | $course3options = array('numsections' => 8, | |
379 | 'hiddensections' => 1, | |
380 | 'coursedisplay' => 1); | |
8d8d4da4 | 381 | $course3['courseformatoptions'] = array(); |
0e984d98 | 382 | foreach ($course3options as $key => $value) { |
8d8d4da4 | 383 | $course3['courseformatoptions'][] = array('name' => $key, 'value' => $value); |
0e984d98 | 384 | } |
821676f5 | 385 | $courses = array($course1, $course2, $course3); |
2a7a0216 JM |
386 | |
387 | $createdcourses = core_course_external::create_courses($courses); | |
388 | ||
fb695f6e JM |
389 | // We need to execute the return values cleaning process to simulate the web service server. |
390 | $createdcourses = external_api::clean_returnvalue(core_course_external::create_courses_returns(), $createdcourses); | |
391 | ||
2a7a0216 | 392 | // Check that right number of courses were created. |
821676f5 | 393 | $this->assertEquals(3, count($createdcourses)); |
2a7a0216 JM |
394 | |
395 | // Check that the courses were correctly created. | |
396 | foreach ($createdcourses as $createdcourse) { | |
850acb35 | 397 | $courseinfo = course_get_format($createdcourse['id'])->get_course(); |
2a7a0216 JM |
398 | |
399 | if ($createdcourse['shortname'] == $course2['shortname']) { | |
850acb35 MG |
400 | $this->assertEquals($courseinfo->fullname, $course2['fullname']); |
401 | $this->assertEquals($courseinfo->shortname, $course2['shortname']); | |
402 | $this->assertEquals($courseinfo->category, $course2['categoryid']); | |
403 | $this->assertEquals($courseinfo->idnumber, $course2['idnumber']); | |
404 | $this->assertEquals($courseinfo->summary, $course2['summary']); | |
405 | $this->assertEquals($courseinfo->summaryformat, $course2['summaryformat']); | |
406 | $this->assertEquals($courseinfo->format, $course2['format']); | |
407 | $this->assertEquals($courseinfo->showgrades, $course2['showgrades']); | |
408 | $this->assertEquals($courseinfo->newsitems, $course2['newsitems']); | |
409 | $this->assertEquals($courseinfo->startdate, $course2['startdate']); | |
410 | $this->assertEquals($courseinfo->numsections, $course2['numsections']); | |
411 | $this->assertEquals($courseinfo->maxbytes, $course2['maxbytes']); | |
412 | $this->assertEquals($courseinfo->showreports, $course2['showreports']); | |
413 | $this->assertEquals($courseinfo->visible, $course2['visible']); | |
414 | $this->assertEquals($courseinfo->hiddensections, $course2['hiddensections']); | |
415 | $this->assertEquals($courseinfo->groupmode, $course2['groupmode']); | |
416 | $this->assertEquals($courseinfo->groupmodeforce, $course2['groupmodeforce']); | |
417 | $this->assertEquals($courseinfo->defaultgroupingid, $course2['defaultgroupingid']); | |
418 | $this->assertEquals($courseinfo->completionnotify, $course2['completionnotify']); | |
419 | $this->assertEquals($courseinfo->lang, $course2['lang']); | |
141e7d87 | 420 | $this->assertEquals($courseinfo->theme, $course2['forcetheme']); |
2a7a0216 | 421 | |
821676f5 JM |
422 | // We enabled completion at the beginning of the test. |
423 | $this->assertEquals($courseinfo->enablecompletion, $course2['enablecompletion']); | |
2a7a0216 JM |
424 | |
425 | } else if ($createdcourse['shortname'] == $course1['shortname']) { | |
426 | $courseconfig = get_config('moodlecourse'); | |
850acb35 MG |
427 | $this->assertEquals($courseinfo->fullname, $course1['fullname']); |
428 | $this->assertEquals($courseinfo->shortname, $course1['shortname']); | |
429 | $this->assertEquals($courseinfo->category, $course1['categoryid']); | |
430 | $this->assertEquals($courseinfo->summaryformat, FORMAT_HTML); | |
431 | $this->assertEquals($courseinfo->format, $courseconfig->format); | |
432 | $this->assertEquals($courseinfo->showgrades, $courseconfig->showgrades); | |
433 | $this->assertEquals($courseinfo->newsitems, $courseconfig->newsitems); | |
434 | $this->assertEquals($courseinfo->maxbytes, $courseconfig->maxbytes); | |
435 | $this->assertEquals($courseinfo->showreports, $courseconfig->showreports); | |
436 | $this->assertEquals($courseinfo->groupmode, $courseconfig->groupmode); | |
437 | $this->assertEquals($courseinfo->groupmodeforce, $courseconfig->groupmodeforce); | |
438 | $this->assertEquals($courseinfo->defaultgroupingid, 0); | |
0e984d98 | 439 | } else if ($createdcourse['shortname'] == $course3['shortname']) { |
850acb35 MG |
440 | $this->assertEquals($courseinfo->fullname, $course3['fullname']); |
441 | $this->assertEquals($courseinfo->shortname, $course3['shortname']); | |
442 | $this->assertEquals($courseinfo->category, $course3['categoryid']); | |
443 | $this->assertEquals($courseinfo->format, $course3['format']); | |
444 | $this->assertEquals($courseinfo->hiddensections, $course3options['hiddensections']); | |
445 | $this->assertEquals($courseinfo->numsections, $course3options['numsections']); | |
446 | $this->assertEquals($courseinfo->coursedisplay, $course3options['coursedisplay']); | |
2a7a0216 JM |
447 | } else { |
448 | throw moodle_exception('Unexpected shortname'); | |
449 | } | |
450 | } | |
451 | ||
452 | // Call without required capability | |
453 | $this->unassignUserCapability('moodle/course:create', $contextid, $roleid); | |
454 | $this->setExpectedException('required_capability_exception'); | |
455 | $createdsubcats = core_course_external::create_courses($courses); | |
456 | } | |
457 | ||
458 | /** | |
459 | * Test delete_courses | |
460 | */ | |
461 | public function test_delete_courses() { | |
462 | global $DB, $USER; | |
463 | ||
464 | $this->resetAfterTest(true); | |
465 | ||
466 | // Admin can delete a course. | |
467 | $this->setAdminUser(); | |
468 | // Validate_context() will fail as the email is not set by $this->setAdminUser(). | |
469 | $USER->email = 'emailtopass@contextvalidation.me'; | |
470 | ||
471 | $course1 = self::getDataGenerator()->create_course(); | |
472 | $course2 = self::getDataGenerator()->create_course(); | |
473 | $course3 = self::getDataGenerator()->create_course(); | |
474 | ||
475 | // Delete courses. | |
476 | core_course_external::delete_courses(array($course1->id, $course2->id)); | |
477 | ||
478 | // Check $course 1 and 2 are deleted. | |
479 | $notdeletedcount = $DB->count_records_select('course', | |
480 | 'id IN ( ' . $course1->id . ',' . $course2->id . ')'); | |
481 | $this->assertEquals(0, $notdeletedcount); | |
482 | ||
483 | // Fail when the user is not allow to access the course (enrolled) or is not admin. | |
484 | $this->setGuestUser(); | |
485 | $this->setExpectedException('require_login_exception'); | |
486 | $createdsubcats = core_course_external::delete_courses(array($course3->id)); | |
487 | } | |
488 | ||
489 | /** | |
490 | * Test get_courses | |
491 | */ | |
492 | public function test_get_courses () { | |
493 | global $DB; | |
494 | ||
495 | $this->resetAfterTest(true); | |
496 | ||
7d6c58bc | 497 | $generatedcourses = array(); |
2a7a0216 JM |
498 | $coursedata['idnumber'] = 'idnumbercourse1'; |
499 | $coursedata['fullname'] = 'Course 1 for PHPunit test'; | |
500 | $coursedata['summary'] = 'Course 1 description'; | |
501 | $coursedata['summaryformat'] = FORMAT_MOODLE; | |
502 | $course1 = self::getDataGenerator()->create_course($coursedata); | |
7d6c58bc | 503 | $generatedcourses[$course1->id] = $course1; |
2a7a0216 | 504 | $course2 = self::getDataGenerator()->create_course(); |
7d6c58bc | 505 | $generatedcourses[$course2->id] = $course2; |
0e984d98 | 506 | $course3 = self::getDataGenerator()->create_course(array('format' => 'topics')); |
7d6c58bc | 507 | $generatedcourses[$course3->id] = $course3; |
2a7a0216 JM |
508 | |
509 | // Set the required capabilities by the external function. | |
510 | $context = context_system::instance(); | |
511 | $roleid = $this->assignUserCapability('moodle/course:view', $context->id); | |
512 | $this->assignUserCapability('moodle/course:update', | |
513 | context_course::instance($course1->id)->id, $roleid); | |
514 | $this->assignUserCapability('moodle/course:update', | |
515 | context_course::instance($course2->id)->id, $roleid); | |
516 | $this->assignUserCapability('moodle/course:update', | |
517 | context_course::instance($course3->id)->id, $roleid); | |
518 | ||
519 | $courses = core_course_external::get_courses(array('ids' => | |
520 | array($course1->id, $course2->id))); | |
521 | ||
fb695f6e JM |
522 | // We need to execute the return values cleaning process to simulate the web service server. |
523 | $courses = external_api::clean_returnvalue(core_course_external::get_courses_returns(), $courses); | |
524 | ||
2a7a0216 JM |
525 | // Check we retrieve the good total number of categories. |
526 | $this->assertEquals(2, count($courses)); | |
527 | ||
7d6c58bc JM |
528 | foreach ($courses as $course) { |
529 | $dbcourse = $generatedcourses[$course['id']]; | |
530 | $this->assertEquals($course['idnumber'], $dbcourse->idnumber); | |
531 | $this->assertEquals($course['fullname'], $dbcourse->fullname); | |
532 | $this->assertEquals($course['summary'], $dbcourse->summary); | |
533 | $this->assertEquals($course['summaryformat'], FORMAT_HTML); | |
534 | $this->assertEquals($course['shortname'], $dbcourse->shortname); | |
535 | $this->assertEquals($course['categoryid'], $dbcourse->category); | |
536 | $this->assertEquals($course['format'], $dbcourse->format); | |
537 | $this->assertEquals($course['showgrades'], $dbcourse->showgrades); | |
538 | $this->assertEquals($course['newsitems'], $dbcourse->newsitems); | |
539 | $this->assertEquals($course['startdate'], $dbcourse->startdate); | |
540 | $this->assertEquals($course['numsections'], $dbcourse->numsections); | |
541 | $this->assertEquals($course['maxbytes'], $dbcourse->maxbytes); | |
542 | $this->assertEquals($course['showreports'], $dbcourse->showreports); | |
543 | $this->assertEquals($course['visible'], $dbcourse->visible); | |
544 | $this->assertEquals($course['hiddensections'], $dbcourse->hiddensections); | |
545 | $this->assertEquals($course['groupmode'], $dbcourse->groupmode); | |
546 | $this->assertEquals($course['groupmodeforce'], $dbcourse->groupmodeforce); | |
547 | $this->assertEquals($course['defaultgroupingid'], $dbcourse->defaultgroupingid); | |
548 | $this->assertEquals($course['completionnotify'], $dbcourse->completionnotify); | |
549 | $this->assertEquals($course['lang'], $dbcourse->lang); | |
550 | $this->assertEquals($course['forcetheme'], $dbcourse->theme); | |
7d6c58bc | 551 | $this->assertEquals($course['enablecompletion'], $dbcourse->enablecompletion); |
0e984d98 | 552 | if ($dbcourse->format === 'topics') { |
8d8d4da4 MG |
553 | $this->assertEquals($course['courseformatoptions'], array( |
554 | array('name' => 'numsections', 'value' => $dbcourse->numsections), | |
555 | array('name' => 'hiddensections', 'value' => $dbcourse->hiddensections), | |
556 | array('name' => 'coursedisplay', 'value' => $dbcourse->coursedisplay), | |
0e984d98 MG |
557 | )); |
558 | } | |
7d6c58bc | 559 | } |
2a7a0216 JM |
560 | |
561 | // Get all courses in the DB | |
562 | $courses = core_course_external::get_courses(array()); | |
fb695f6e JM |
563 | |
564 | // We need to execute the return values cleaning process to simulate the web service server. | |
565 | $courses = external_api::clean_returnvalue(core_course_external::get_courses_returns(), $courses); | |
566 | ||
2a7a0216 JM |
567 | $this->assertEquals($DB->count_records('course'), count($courses)); |
568 | } | |
569 | ||
570 | /** | |
571 | * Test get_course_contents | |
572 | */ | |
573 | public function test_get_course_contents() { | |
574 | $this->resetAfterTest(true); | |
575 | ||
576 | $course = self::getDataGenerator()->create_course(); | |
487bc1b6 JM |
577 | $forumdescription = 'This is the forum description'; |
578 | $forum = $this->getDataGenerator()->create_module('forum', | |
579 | array('course'=>$course->id, 'intro' => $forumdescription), | |
580 | array('showdescription' => true)); | |
2a7a0216 | 581 | $forumcm = get_coursemodule_from_id('forum', $forum->cmid); |
2a7a0216 | 582 | $data = $this->getDataGenerator()->create_module('data', array('assessed'=>1, 'scale'=>100, 'course'=>$course->id)); |
2a7a0216 JM |
583 | $datacm = get_coursemodule_from_instance('page', $data->id); |
584 | $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id)); | |
2a7a0216 | 585 | $pagecm = get_coursemodule_from_instance('page', $page->id); |
487bc1b6 JM |
586 | $labeldescription = 'This is a very long label to test if more than 50 characters are returned. |
587 | So bla bla bla bla <b>bold bold bold</b> bla bla bla bla.'; | |
588 | $label = $this->getDataGenerator()->create_module('label', array('course' => $course->id, | |
589 | 'intro' => $labeldescription)); | |
590 | $labelcm = get_coursemodule_from_instance('label', $label->id); | |
e13c152e JL |
591 | $url = $this->getDataGenerator()->create_module('url', array('course' => $course->id, |
592 | 'name' => 'URL: % & $ ../')); | |
2a7a0216 JM |
593 | |
594 | // Set the required capabilities by the external function. | |
595 | $context = context_course::instance($course->id); | |
596 | $roleid = $this->assignUserCapability('moodle/course:view', $context->id); | |
597 | $this->assignUserCapability('moodle/course:update', $context->id, $roleid); | |
598 | ||
487bc1b6 | 599 | $sections = core_course_external::get_course_contents($course->id, array()); |
2a7a0216 | 600 | |
fb695f6e | 601 | // We need to execute the return values cleaning process to simulate the web service server. |
487bc1b6 JM |
602 | $sections = external_api::clean_returnvalue(core_course_external::get_course_contents_returns(), $sections); |
603 | ||
604 | // Check that forum and label descriptions are correctly returned. | |
605 | $firstsection = array_pop($sections); | |
606 | $modinfo = get_fast_modinfo($course); | |
607 | $testexecuted = 0; | |
608 | foreach($firstsection['modules'] as $module) { | |
609 | if ($module['id'] == $forumcm->id and $module['modname'] == 'forum') { | |
610 | $cm = $modinfo->cms[$forumcm->id]; | |
73ee2fda | 611 | $formattedtext = format_text($cm->content, FORMAT_HTML, |
487bc1b6 JM |
612 | array('noclean' => true, 'para' => false, 'filter' => false)); |
613 | $this->assertEquals($formattedtext, $module['description']); | |
614 | $testexecuted = $testexecuted + 1; | |
615 | } else if ($module['id'] == $labelcm->id and $module['modname'] == 'label') { | |
616 | $cm = $modinfo->cms[$labelcm->id]; | |
73ee2fda | 617 | $formattedtext = format_text($cm->content, FORMAT_HTML, |
487bc1b6 JM |
618 | array('noclean' => true, 'para' => false, 'filter' => false)); |
619 | $this->assertEquals($formattedtext, $module['description']); | |
620 | $testexecuted = $testexecuted + 1; | |
621 | } | |
622 | } | |
623 | $this->assertEquals(2, $testexecuted); | |
fb695f6e | 624 | |
cdd9c80f MG |
625 | // Check that the only return section has the 5 created modules |
626 | $this->assertEquals(5, count($firstsection['modules'])); | |
2a7a0216 JM |
627 | } |
628 | ||
629 | /** | |
630 | * Test duplicate_course | |
631 | */ | |
632 | public function test_duplicate_course() { | |
633 | $this->resetAfterTest(true); | |
634 | ||
635 | // Create one course with three modules. | |
636 | $course = self::getDataGenerator()->create_course(); | |
637 | $forum = $this->getDataGenerator()->create_module('forum', array('course'=>$course->id)); | |
638 | $forumcm = get_coursemodule_from_id('forum', $forum->cmid); | |
639 | $forumcontext = context_module::instance($forum->cmid); | |
640 | $data = $this->getDataGenerator()->create_module('data', array('assessed'=>1, 'scale'=>100, 'course'=>$course->id)); | |
641 | $datacontext = context_module::instance($data->cmid); | |
642 | $datacm = get_coursemodule_from_instance('page', $data->id); | |
643 | $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id)); | |
644 | $pagecontext = context_module::instance($page->cmid); | |
645 | $pagecm = get_coursemodule_from_instance('page', $page->id); | |
646 | ||
647 | // Set the required capabilities by the external function. | |
648 | $coursecontext = context_course::instance($course->id); | |
649 | $categorycontext = context_coursecat::instance($course->category); | |
650 | $roleid = $this->assignUserCapability('moodle/course:create', $categorycontext->id); | |
651 | $this->assignUserCapability('moodle/course:view', $categorycontext->id, $roleid); | |
652 | $this->assignUserCapability('moodle/restore:restorecourse', $categorycontext->id, $roleid); | |
653 | $this->assignUserCapability('moodle/backup:backupcourse', $coursecontext->id, $roleid); | |
654 | $this->assignUserCapability('moodle/backup:configure', $coursecontext->id, $roleid); | |
655 | // Optional capabilities to copy user data. | |
656 | $this->assignUserCapability('moodle/backup:userinfo', $coursecontext->id, $roleid); | |
657 | $this->assignUserCapability('moodle/restore:userinfo', $categorycontext->id, $roleid); | |
658 | ||
659 | $newcourse['fullname'] = 'Course duplicate'; | |
660 | $newcourse['shortname'] = 'courseduplicate'; | |
661 | $newcourse['categoryid'] = $course->category; | |
662 | $newcourse['visible'] = true; | |
663 | $newcourse['options'][] = array('name' => 'users', 'value' => true); | |
664 | ||
665 | $duplicate = core_course_external::duplicate_course($course->id, $newcourse['fullname'], | |
666 | $newcourse['shortname'], $newcourse['categoryid'], $newcourse['visible'], $newcourse['options']); | |
667 | ||
fb695f6e JM |
668 | // We need to execute the return values cleaning process to simulate the web service server. |
669 | $duplicate = external_api::clean_returnvalue(core_course_external::duplicate_course_returns(), $duplicate); | |
670 | ||
2a7a0216 JM |
671 | // Check that the course has been duplicated. |
672 | $this->assertEquals($newcourse['shortname'], $duplicate['shortname']); | |
673 | } | |
791723c3 RT |
674 | |
675 | /** | |
676 | * Test update_courses | |
677 | */ | |
678 | public function test_update_courses() { | |
a182f88f EL |
679 | global $DB, $CFG, $USER, $COURSE; |
680 | ||
681 | // Get current $COURSE to be able to restore it later (defaults to $SITE). We need this | |
682 | // trick because we are both updating and getting (for testing) course information | |
683 | // in the same request and core_course_external::update_courses() | |
684 | // is overwriting $COURSE all over the time with OLD values, so later | |
685 | // use of get_course() fetches those OLD values instead of the updated ones. | |
686 | // See MDL-39723 for more info. | |
687 | $origcourse = clone($COURSE); | |
791723c3 RT |
688 | |
689 | $this->resetAfterTest(true); | |
690 | ||
691 | // Set the required capabilities by the external function. | |
692 | $contextid = context_system::instance()->id; | |
693 | $roleid = $this->assignUserCapability('moodle/course:update', $contextid); | |
694 | $this->assignUserCapability('moodle/course:changecategory', $contextid, $roleid); | |
695 | $this->assignUserCapability('moodle/course:changefullname', $contextid, $roleid); | |
696 | $this->assignUserCapability('moodle/course:changeshortname', $contextid, $roleid); | |
697 | $this->assignUserCapability('moodle/course:changeidnumber', $contextid, $roleid); | |
698 | $this->assignUserCapability('moodle/course:changesummary', $contextid, $roleid); | |
699 | $this->assignUserCapability('moodle/course:visibility', $contextid, $roleid); | |
700 | $this->assignUserCapability('moodle/course:viewhiddencourses', $contextid, $roleid); | |
701 | ||
702 | // Create category and course. | |
703 | $category1 = self::getDataGenerator()->create_category(); | |
704 | $category2 = self::getDataGenerator()->create_category(); | |
705 | $originalcourse1 = self::getDataGenerator()->create_course(); | |
706 | self::getDataGenerator()->enrol_user($USER->id, $originalcourse1->id, $roleid); | |
707 | $originalcourse2 = self::getDataGenerator()->create_course(); | |
708 | self::getDataGenerator()->enrol_user($USER->id, $originalcourse2->id, $roleid); | |
709 | ||
710 | // Course values to be updated. | |
711 | $course1['id'] = $originalcourse1->id; | |
712 | $course1['fullname'] = 'Updated test course 1'; | |
713 | $course1['shortname'] = 'Udestedtestcourse1'; | |
714 | $course1['categoryid'] = $category1->id; | |
715 | $course2['id'] = $originalcourse2->id; | |
716 | $course2['fullname'] = 'Updated test course 2'; | |
717 | $course2['shortname'] = 'Updestedtestcourse2'; | |
718 | $course2['categoryid'] = $category2->id; | |
719 | $course2['idnumber'] = 'Updatedidnumber2'; | |
720 | $course2['summary'] = 'Updaated description for course 2'; | |
721 | $course2['summaryformat'] = FORMAT_HTML; | |
722 | $course2['format'] = 'topics'; | |
723 | $course2['showgrades'] = 1; | |
724 | $course2['newsitems'] = 3; | |
725 | $course2['startdate'] = 1420092000; // 01/01/2015. | |
726 | $course2['numsections'] = 4; | |
727 | $course2['maxbytes'] = 100000; | |
728 | $course2['showreports'] = 1; | |
729 | $course2['visible'] = 0; | |
730 | $course2['hiddensections'] = 0; | |
731 | $course2['groupmode'] = 0; | |
732 | $course2['groupmodeforce'] = 0; | |
733 | $course2['defaultgroupingid'] = 0; | |
734 | $course2['enablecompletion'] = 1; | |
735 | $course2['lang'] = 'en'; | |
736 | $course2['forcetheme'] = 'base'; | |
737 | $courses = array($course1, $course2); | |
738 | ||
739 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
a182f88f | 740 | $COURSE = $origcourse; // Restore $COURSE. Instead of using the OLD one set by the previous line. |
791723c3 RT |
741 | |
742 | // Check that right number of courses were created. | |
743 | $this->assertEquals(0, count($updatedcoursewarnings['warnings'])); | |
744 | ||
745 | // Check that the courses were correctly created. | |
746 | foreach ($courses as $course) { | |
747 | $courseinfo = course_get_format($course['id'])->get_course(); | |
748 | if ($course['id'] == $course2['id']) { | |
749 | $this->assertEquals($course2['fullname'], $courseinfo->fullname); | |
750 | $this->assertEquals($course2['shortname'], $courseinfo->shortname); | |
751 | $this->assertEquals($course2['categoryid'], $courseinfo->category); | |
752 | $this->assertEquals($course2['idnumber'], $courseinfo->idnumber); | |
753 | $this->assertEquals($course2['summary'], $courseinfo->summary); | |
754 | $this->assertEquals($course2['summaryformat'], $courseinfo->summaryformat); | |
755 | $this->assertEquals($course2['format'], $courseinfo->format); | |
756 | $this->assertEquals($course2['showgrades'], $courseinfo->showgrades); | |
757 | $this->assertEquals($course2['newsitems'], $courseinfo->newsitems); | |
758 | $this->assertEquals($course2['startdate'], $courseinfo->startdate); | |
759 | $this->assertEquals($course2['numsections'], $courseinfo->numsections); | |
760 | $this->assertEquals($course2['maxbytes'], $courseinfo->maxbytes); | |
761 | $this->assertEquals($course2['showreports'], $courseinfo->showreports); | |
762 | $this->assertEquals($course2['visible'], $courseinfo->visible); | |
763 | $this->assertEquals($course2['hiddensections'], $courseinfo->hiddensections); | |
764 | $this->assertEquals($course2['groupmode'], $courseinfo->groupmode); | |
765 | $this->assertEquals($course2['groupmodeforce'], $courseinfo->groupmodeforce); | |
766 | $this->assertEquals($course2['defaultgroupingid'], $courseinfo->defaultgroupingid); | |
767 | $this->assertEquals($course2['lang'], $courseinfo->lang); | |
768 | ||
769 | if (!empty($CFG->allowcoursethemes)) { | |
770 | $this->assertEquals($course2['forcetheme'], $courseinfo->theme); | |
771 | } | |
772 | ||
773 | if (completion_info::is_enabled_for_site()) { | |
774 | $this->assertEquals($course2['enabledcompletion'], $courseinfo->enablecompletion); | |
791723c3 RT |
775 | } |
776 | } else if ($course['id'] == $course1['id']) { | |
777 | $this->assertEquals($course1['fullname'], $courseinfo->fullname); | |
778 | $this->assertEquals($course1['shortname'], $courseinfo->shortname); | |
779 | $this->assertEquals($course1['categoryid'], $courseinfo->category); | |
780 | $this->assertEquals(FORMAT_MOODLE, $courseinfo->summaryformat); | |
781 | $this->assertEquals('topics', $courseinfo->format); | |
782 | $this->assertEquals(5, $courseinfo->numsections); | |
783 | $this->assertEquals(0, $courseinfo->newsitems); | |
784 | $this->assertEquals(FORMAT_MOODLE, $courseinfo->summaryformat); | |
785 | } else { | |
786 | throw moodle_exception('Unexpected shortname'); | |
787 | } | |
788 | } | |
789 | ||
790 | $courses = array($course1); | |
791 | // Try update course without update capability. | |
792 | $user = self::getDataGenerator()->create_user(); | |
793 | $this->setUser($user); | |
794 | $this->unassignUserCapability('moodle/course:update', $contextid, $roleid); | |
795 | self::getDataGenerator()->enrol_user($user->id, $course1['id'], $roleid); | |
796 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
797 | $this->assertEquals(1, count($updatedcoursewarnings['warnings'])); | |
798 | ||
799 | // Try update course category without capability. | |
800 | $this->assignUserCapability('moodle/course:update', $contextid, $roleid); | |
801 | $this->unassignUserCapability('moodle/course:changecategory', $contextid, $roleid); | |
802 | $user = self::getDataGenerator()->create_user(); | |
803 | $this->setUser($user); | |
804 | self::getDataGenerator()->enrol_user($user->id, $course1['id'], $roleid); | |
805 | $course1['categoryid'] = $category2->id; | |
806 | $courses = array($course1); | |
807 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
808 | $this->assertEquals(1, count($updatedcoursewarnings['warnings'])); | |
809 | ||
810 | // Try update course fullname without capability. | |
811 | $this->assignUserCapability('moodle/course:changecategory', $contextid, $roleid); | |
812 | $this->unassignUserCapability('moodle/course:changefullname', $contextid, $roleid); | |
813 | $user = self::getDataGenerator()->create_user(); | |
814 | $this->setUser($user); | |
815 | self::getDataGenerator()->enrol_user($user->id, $course1['id'], $roleid); | |
816 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
817 | $this->assertEquals(0, count($updatedcoursewarnings['warnings'])); | |
818 | $course1['fullname'] = 'Testing fullname without permission'; | |
819 | $courses = array($course1); | |
820 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
821 | $this->assertEquals(1, count($updatedcoursewarnings['warnings'])); | |
822 | ||
823 | // Try update course shortname without capability. | |
824 | $this->assignUserCapability('moodle/course:changefullname', $contextid, $roleid); | |
825 | $this->unassignUserCapability('moodle/course:changeshortname', $contextid, $roleid); | |
826 | $user = self::getDataGenerator()->create_user(); | |
827 | $this->setUser($user); | |
828 | self::getDataGenerator()->enrol_user($user->id, $course1['id'], $roleid); | |
829 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
830 | $this->assertEquals(0, count($updatedcoursewarnings['warnings'])); | |
831 | $course1['shortname'] = 'Testing shortname without permission'; | |
832 | $courses = array($course1); | |
833 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
834 | $this->assertEquals(1, count($updatedcoursewarnings['warnings'])); | |
835 | ||
836 | // Try update course idnumber without capability. | |
837 | $this->assignUserCapability('moodle/course:changeshortname', $contextid, $roleid); | |
838 | $this->unassignUserCapability('moodle/course:changeidnumber', $contextid, $roleid); | |
839 | $user = self::getDataGenerator()->create_user(); | |
840 | $this->setUser($user); | |
841 | self::getDataGenerator()->enrol_user($user->id, $course1['id'], $roleid); | |
842 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
843 | $this->assertEquals(0, count($updatedcoursewarnings['warnings'])); | |
844 | $course1['idnumber'] = 'NEWIDNUMBER'; | |
845 | $courses = array($course1); | |
846 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
847 | $this->assertEquals(1, count($updatedcoursewarnings['warnings'])); | |
848 | ||
849 | // Try update course summary without capability. | |
850 | $this->assignUserCapability('moodle/course:changeidnumber', $contextid, $roleid); | |
851 | $this->unassignUserCapability('moodle/course:changesummary', $contextid, $roleid); | |
852 | $user = self::getDataGenerator()->create_user(); | |
853 | $this->setUser($user); | |
854 | self::getDataGenerator()->enrol_user($user->id, $course1['id'], $roleid); | |
855 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
856 | $this->assertEquals(0, count($updatedcoursewarnings['warnings'])); | |
857 | $course1['summary'] = 'New summary'; | |
858 | $courses = array($course1); | |
859 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
860 | $this->assertEquals(1, count($updatedcoursewarnings['warnings'])); | |
861 | ||
862 | // Try update course with invalid summary format. | |
863 | $this->assignUserCapability('moodle/course:changesummary', $contextid, $roleid); | |
864 | $user = self::getDataGenerator()->create_user(); | |
865 | $this->setUser($user); | |
866 | self::getDataGenerator()->enrol_user($user->id, $course1['id'], $roleid); | |
867 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
868 | $this->assertEquals(0, count($updatedcoursewarnings['warnings'])); | |
869 | $course1['summaryformat'] = 10; | |
870 | $courses = array($course1); | |
871 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
872 | $this->assertEquals(1, count($updatedcoursewarnings['warnings'])); | |
873 | ||
874 | // Try update course visibility without capability. | |
875 | $this->unassignUserCapability('moodle/course:visibility', $contextid, $roleid); | |
876 | $user = self::getDataGenerator()->create_user(); | |
877 | $this->setUser($user); | |
878 | self::getDataGenerator()->enrol_user($user->id, $course1['id'], $roleid); | |
879 | $course1['summaryformat'] = FORMAT_MOODLE; | |
880 | $courses = array($course1); | |
881 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
882 | $this->assertEquals(0, count($updatedcoursewarnings['warnings'])); | |
883 | $course1['visible'] = 0; | |
884 | $courses = array($course1); | |
885 | $updatedcoursewarnings = core_course_external::update_courses($courses); | |
886 | $this->assertEquals(1, count($updatedcoursewarnings['warnings'])); | |
887 | } | |
05fc7ccc | 888 | |
79949c1b MN |
889 | /** |
890 | * Test delete course_module. | |
891 | */ | |
892 | public function test_delete_modules() { | |
893 | global $DB; | |
894 | ||
895 | // Ensure we reset the data after this test. | |
896 | $this->resetAfterTest(true); | |
897 | ||
898 | // Create a user. | |
899 | $user = self::getDataGenerator()->create_user(); | |
900 | ||
901 | // Set the tests to run as the user. | |
902 | self::setUser($user); | |
903 | ||
904 | // Create a course to add the modules. | |
905 | $course = self::getDataGenerator()->create_course(); | |
906 | ||
907 | // Create two test modules. | |
908 | $record = new stdClass(); | |
909 | $record->course = $course->id; | |
910 | $module1 = self::getDataGenerator()->create_module('forum', $record); | |
40cb4879 | 911 | $module2 = self::getDataGenerator()->create_module('assign', $record); |
79949c1b MN |
912 | |
913 | // Check the forum was correctly created. | |
914 | $this->assertEquals(1, $DB->count_records('forum', array('id' => $module1->id))); | |
915 | ||
916 | // Check the assignment was correctly created. | |
40cb4879 | 917 | $this->assertEquals(1, $DB->count_records('assign', array('id' => $module2->id))); |
79949c1b MN |
918 | |
919 | // Check data exists in the course modules table. | |
920 | $this->assertEquals(2, $DB->count_records_select('course_modules', 'id = :module1 OR id = :module2', | |
921 | array('module1' => $module1->cmid, 'module2' => $module2->cmid))); | |
922 | ||
923 | // Enrol the user in the course. | |
924 | $enrol = enrol_get_plugin('manual'); | |
925 | $enrolinstances = enrol_get_instances($course->id, true); | |
926 | foreach ($enrolinstances as $courseenrolinstance) { | |
927 | if ($courseenrolinstance->enrol == "manual") { | |
928 | $instance = $courseenrolinstance; | |
929 | break; | |
930 | } | |
931 | } | |
932 | $enrol->enrol_user($instance, $user->id); | |
933 | ||
934 | // Assign capabilities to delete module 1. | |
935 | $modcontext = context_module::instance($module1->cmid); | |
936 | $this->assignUserCapability('moodle/course:manageactivities', $modcontext->id); | |
937 | ||
938 | // Assign capabilities to delete module 2. | |
939 | $modcontext = context_module::instance($module2->cmid); | |
940 | $newrole = create_role('Role 2', 'role2', 'Role 2 description'); | |
941 | $this->assignUserCapability('moodle/course:manageactivities', $modcontext->id, $newrole); | |
942 | ||
943 | // Deleting these module instances. | |
944 | core_course_external::delete_modules(array($module1->cmid, $module2->cmid)); | |
945 | ||
946 | // Check the forum was deleted. | |
947 | $this->assertEquals(0, $DB->count_records('forum', array('id' => $module1->id))); | |
948 | ||
949 | // Check the assignment was deleted. | |
40cb4879 | 950 | $this->assertEquals(0, $DB->count_records('assign', array('id' => $module2->id))); |
79949c1b MN |
951 | |
952 | // Check we retrieve no data in the course modules table. | |
953 | $this->assertEquals(0, $DB->count_records_select('course_modules', 'id = :module1 OR id = :module2', | |
954 | array('module1' => $module1->cmid, 'module2' => $module2->cmid))); | |
955 | ||
956 | // Call with non-existent course module id and ensure exception thrown. | |
957 | try { | |
958 | core_course_external::delete_modules(array('1337')); | |
959 | $this->fail('Exception expected due to missing course module.'); | |
960 | } catch (dml_missing_record_exception $e) { | |
affdc3b7 | 961 | $this->assertEquals('invalidcoursemodule', $e->errorcode); |
79949c1b MN |
962 | } |
963 | ||
964 | // Create two modules. | |
965 | $module1 = self::getDataGenerator()->create_module('forum', $record); | |
40cb4879 | 966 | $module2 = self::getDataGenerator()->create_module('assign', $record); |
79949c1b MN |
967 | |
968 | // Since these modules were recreated the user will not have capabilities | |
969 | // to delete them, ensure exception is thrown if they try. | |
970 | try { | |
971 | core_course_external::delete_modules(array($module1->cmid, $module2->cmid)); | |
972 | $this->fail('Exception expected due to missing capability.'); | |
973 | } catch (moodle_exception $e) { | |
974 | $this->assertEquals('nopermissions', $e->errorcode); | |
975 | } | |
976 | ||
977 | // Unenrol user from the course. | |
978 | $enrol->unenrol_user($instance, $user->id); | |
979 | ||
980 | // Try and delete modules from the course the user was unenrolled in, make sure exception thrown. | |
981 | try { | |
982 | core_course_external::delete_modules(array($module1->cmid, $module2->cmid)); | |
983 | $this->fail('Exception expected due to being unenrolled from the course.'); | |
984 | } catch (moodle_exception $e) { | |
985 | $this->assertEquals('requireloginerror', $e->errorcode); | |
986 | } | |
987 | } | |
fce10644 DP |
988 | |
989 | /** | |
990 | * Test import_course into an empty course | |
991 | */ | |
992 | public function test_import_course_empty() { | |
993 | global $USER; | |
994 | ||
995 | $this->resetAfterTest(true); | |
996 | ||
997 | $course1 = self::getDataGenerator()->create_course(); | |
998 | $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course1->id, 'name' => 'Forum test')); | |
999 | $page = $this->getDataGenerator()->create_module('page', array('course' => $course1->id, 'name' => 'Page test')); | |
1000 | ||
1001 | $course2 = self::getDataGenerator()->create_course(); | |
1002 | ||
1003 | $course1cms = get_fast_modinfo($course1->id)->get_cms(); | |
1004 | $course2cms = get_fast_modinfo($course2->id)->get_cms(); | |
1005 | ||
1006 | // Verify the state of the courses before we do the import. | |
1007 | $this->assertCount(2, $course1cms); | |
1008 | $this->assertEmpty($course2cms); | |
1009 | ||
1010 | // Setup the user to run the operation (ugly hack because validate_context() will | |
1011 | // fail as the email is not set by $this->setAdminUser()). | |
1012 | $this->setAdminUser(); | |
1013 | $USER->email = 'emailtopass@contextvalidation.me'; | |
1014 | ||
1015 | // Import from course1 to course2. | |
1016 | core_course_external::import_course($course1->id, $course2->id, 0); | |
1017 | ||
1018 | // Verify that now we have two modules in both courses. | |
1019 | $course1cms = get_fast_modinfo($course1->id)->get_cms(); | |
1020 | $course2cms = get_fast_modinfo($course2->id)->get_cms(); | |
1021 | $this->assertCount(2, $course1cms); | |
1022 | $this->assertCount(2, $course2cms); | |
1023 | ||
1024 | // Verify that the names transfered across correctly. | |
1025 | foreach ($course2cms as $cm) { | |
1026 | if ($cm->modname === 'page') { | |
1027 | $this->assertEquals($cm->name, $page->name); | |
1028 | } else if ($cm->modname === 'forum') { | |
1029 | $this->assertEquals($cm->name, $forum->name); | |
1030 | } else { | |
1031 | $this->fail('Unknown CM found.'); | |
1032 | } | |
1033 | } | |
fce10644 DP |
1034 | } |
1035 | ||
1036 | /** | |
1037 | * Test import_course into an filled course | |
1038 | */ | |
1039 | public function test_import_course_filled() { | |
1040 | global $USER; | |
1041 | ||
1042 | $this->resetAfterTest(true); | |
1043 | ||
1044 | // Add forum and page to course1. | |
1045 | $course1 = self::getDataGenerator()->create_course(); | |
1046 | $forum = $this->getDataGenerator()->create_module('forum', array('course'=>$course1->id, 'name' => 'Forum test')); | |
1047 | $page = $this->getDataGenerator()->create_module('page', array('course'=>$course1->id, 'name' => 'Page test')); | |
1048 | ||
1049 | // Add quiz to course 2. | |
1050 | $course2 = self::getDataGenerator()->create_course(); | |
1051 | $quiz = $this->getDataGenerator()->create_module('quiz', array('course'=>$course2->id, 'name' => 'Page test')); | |
1052 | ||
1053 | $course1cms = get_fast_modinfo($course1->id)->get_cms(); | |
1054 | $course2cms = get_fast_modinfo($course2->id)->get_cms(); | |
1055 | ||
1056 | // Verify the state of the courses before we do the import. | |
1057 | $this->assertCount(2, $course1cms); | |
1058 | $this->assertCount(1, $course2cms); | |
1059 | ||
1060 | // Setup the user to run the operation (ugly hack because validate_context() will | |
1061 | // fail as the email is not set by $this->setAdminUser()). | |
1062 | $this->setAdminUser(); | |
1063 | $USER->email = 'emailtopass@contextvalidation.me'; | |
1064 | ||
1065 | // Import from course1 to course2 without deleting content. | |
1066 | core_course_external::import_course($course1->id, $course2->id, 0); | |
1067 | ||
1068 | $course2cms = get_fast_modinfo($course2->id)->get_cms(); | |
1069 | ||
1070 | // Verify that now we have three modules in course2. | |
1071 | $this->assertCount(3, $course2cms); | |
1072 | ||
1073 | // Verify that the names transfered across correctly. | |
1074 | foreach ($course2cms as $cm) { | |
1075 | if ($cm->modname === 'page') { | |
1076 | $this->assertEquals($cm->name, $page->name); | |
1077 | } else if ($cm->modname === 'forum') { | |
1078 | $this->assertEquals($cm->name, $forum->name); | |
1079 | } else if ($cm->modname === 'quiz') { | |
1080 | $this->assertEquals($cm->name, $quiz->name); | |
1081 | } else { | |
1082 | $this->fail('Unknown CM found.'); | |
1083 | } | |
1084 | } | |
fce10644 DP |
1085 | } |
1086 | ||
1087 | /** | |
1088 | * Test import_course with only blocks set to backup | |
1089 | */ | |
1090 | public function test_import_course_blocksonly() { | |
1091 | global $USER, $DB; | |
1092 | ||
1093 | $this->resetAfterTest(true); | |
1094 | ||
1095 | // Add forum and page to course1. | |
1096 | $course1 = self::getDataGenerator()->create_course(); | |
1097 | $course1ctx = context_course::instance($course1->id); | |
1098 | $forum = $this->getDataGenerator()->create_module('forum', array('course'=>$course1->id, 'name' => 'Forum test')); | |
1099 | $block = $this->getDataGenerator()->create_block('online_users', array('parentcontextid' => $course1ctx->id)); | |
1100 | ||
1101 | $course2 = self::getDataGenerator()->create_course(); | |
1102 | $course2ctx = context_course::instance($course2->id); | |
1103 | $initialblockcount = $DB->count_records('block_instances', array('parentcontextid' => $course2ctx->id)); | |
1104 | $initialcmcount = count(get_fast_modinfo($course2->id)->get_cms()); | |
1105 | ||
1106 | // Setup the user to run the operation (ugly hack because validate_context() will | |
1107 | // fail as the email is not set by $this->setAdminUser()). | |
1108 | $this->setAdminUser(); | |
1109 | $USER->email = 'emailtopass@contextvalidation.me'; | |
1110 | ||
1111 | // Import from course1 to course2 without deleting content, but excluding | |
1112 | // activities. | |
1113 | $options = array( | |
1114 | array('name' => 'activities', 'value' => 0), | |
1115 | array('name' => 'blocks', 'value' => 1), | |
1116 | array('name' => 'filters', 'value' => 0), | |
1117 | ); | |
1118 | ||
1119 | core_course_external::import_course($course1->id, $course2->id, 0, $options); | |
1120 | ||
1121 | $newcmcount = count(get_fast_modinfo($course2->id)->get_cms()); | |
1122 | $newblockcount = $DB->count_records('block_instances', array('parentcontextid' => $course2ctx->id)); | |
1123 | // Check that course modules haven't changed, but that blocks have. | |
1124 | $this->assertEquals($initialcmcount, $newcmcount); | |
1125 | $this->assertEquals(($initialblockcount + 1), $newblockcount); | |
fce10644 DP |
1126 | } |
1127 | ||
1128 | /** | |
1129 | * Test import_course into an filled course, deleting content. | |
1130 | */ | |
1131 | public function test_import_course_deletecontent() { | |
1132 | global $USER; | |
1133 | $this->resetAfterTest(true); | |
1134 | ||
1135 | // Add forum and page to course1. | |
1136 | $course1 = self::getDataGenerator()->create_course(); | |
1137 | $forum = $this->getDataGenerator()->create_module('forum', array('course'=>$course1->id, 'name' => 'Forum test')); | |
1138 | $page = $this->getDataGenerator()->create_module('page', array('course'=>$course1->id, 'name' => 'Page test')); | |
1139 | ||
1140 | // Add quiz to course 2. | |
1141 | $course2 = self::getDataGenerator()->create_course(); | |
1142 | $quiz = $this->getDataGenerator()->create_module('quiz', array('course'=>$course2->id, 'name' => 'Page test')); | |
1143 | ||
1144 | $course1cms = get_fast_modinfo($course1->id)->get_cms(); | |
1145 | $course2cms = get_fast_modinfo($course2->id)->get_cms(); | |
1146 | ||
1147 | // Verify the state of the courses before we do the import. | |
1148 | $this->assertCount(2, $course1cms); | |
1149 | $this->assertCount(1, $course2cms); | |
1150 | ||
1151 | // Setup the user to run the operation (ugly hack because validate_context() will | |
1152 | // fail as the email is not set by $this->setAdminUser()). | |
1153 | $this->setAdminUser(); | |
1154 | $USER->email = 'emailtopass@contextvalidation.me'; | |
1155 | ||
1156 | // Import from course1 to course2, deleting content. | |
1157 | core_course_external::import_course($course1->id, $course2->id, 1); | |
1158 | ||
1159 | $course2cms = get_fast_modinfo($course2->id)->get_cms(); | |
1160 | ||
1161 | // Verify that now we have two modules in course2. | |
1162 | $this->assertCount(2, $course2cms); | |
1163 | ||
1164 | // Verify that the course only contains the imported modules. | |
1165 | foreach ($course2cms as $cm) { | |
1166 | if ($cm->modname === 'page') { | |
1167 | $this->assertEquals($cm->name, $page->name); | |
1168 | } else if ($cm->modname === 'forum') { | |
1169 | $this->assertEquals($cm->name, $forum->name); | |
1170 | } else { | |
1171 | $this->fail('Unknown CM found: '.$cm->name); | |
1172 | } | |
1173 | } | |
fce10644 DP |
1174 | } |
1175 | ||
1176 | /** | |
1177 | * Ensure import_course handles incorrect deletecontent option correctly. | |
1178 | */ | |
1179 | public function test_import_course_invalid_deletecontent_option() { | |
1180 | $this->resetAfterTest(true); | |
1181 | ||
1182 | $course1 = self::getDataGenerator()->create_course(); | |
1183 | $course2 = self::getDataGenerator()->create_course(); | |
1184 | ||
1185 | $this->setExpectedException('moodle_exception', get_string('invalidextparam', 'webservice', -1)); | |
1186 | // Import from course1 to course2, with invalid option | |
1187 | core_course_external::import_course($course1->id, $course2->id, -1);; | |
1188 | } | |
2a7a0216 | 1189 | } |